In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly shows you the "sample analysis of cgo in golang", which is easy to understand and clear. I hope it can help you solve your doubts. Let the editor lead you to study and study the "sample analysis of cgo in golang".
The basic principle of GO C modulation CGO is the way to realize the interoperation between Go and C, which includes two processes of Go C modulation and C modulation Go. The process of adjusting C by Go is relatively simple. For a function add3 defined in C, you need to explicitly use the C.add3 call when calling in Go. Where C is a pseudo package introduced in the program.
The import "C" in the code is the pseudo package used in Go. This package is not real and will not be seen by the compile component of Go. It will be captured by the CGO tool before compilation and do some code rewriting and pile file generation.
CGO provides a mechanism for golang and C language to call each other. Some third-party libraries may only have the implementation of Cgolang +, and an implementation entirely in pure CGO may be a huge project, so CGO will come in handy. You can get through the interface of CGO in golang to call C, and the interface of C++ can be wrapped in C and provided to golang. The called C code can be provided directly as source code or packaged with static or dynamic libraries at compile time. Static libraries are recommended to facilitate code isolation, and compiled binaries do not rely on dynamic libraries for easy distribution, which is in line with the philosophy of golang.
Basic numerical type
Golang's basic numeric type memory model, like the C language, is a series of bytes (1 / 2 / 4 / 8 bytes). So when you pass a numeric type, you can directly convert the basic numeric type of golang to the corresponding CGO type and then pass it to the C function call, and vice versa:
Package main
/ *
# include
Static int32_t add (int32_t a, int32_t b) {
Return a + b
}
, /
Import "C"
Import "fmt"
Func main () {
Var a, b int32 = 1,2
Var c int32 = int32 (C.add (C.int32_t (a), C.int32_t (b))
Fmt.Println (c) / / 3
}
The comparison table of basic numerical type conversion for golang and C is as follows:
C language type CGO type Go language type
Char C.char byte
Singed char C.schar int8
Unsigned char C.uchar uint8
Short C.short int16
Unsigned short C.ushort uint16
Int C.int int32
Unsigned int C.uint uint32
Long C.long int32
Unsigned long C.ulong uint32
Longlong int C.longlong int64
Unsigned longlong int C.ulonglong uint64
Float C.float float32
Double C.double float64
Size_t C.size_t uint
Note that the shaping in C, such as int, does not define a specific word length in the standard, but generally defaults to 4 bytes. C.int in the corresponding CGO type clearly defines a word length of 4, but the int word length in golang is 8, so the corresponding golang type is not int but int32. In order to avoid misuse, C code had better use the numerical type of C99 standard.
Slicing in golang looks a bit like an array in C, but the actual memory model is a little different. The array in C is a continuous piece of memory, and the value of the array is actually the first address of that memory. The memory model of the golang slice is as follows (see source code $GOROOT/src/runtime/chan.go
Array len cap
| |
V
Data
Due to the difference of the underlying memory model, the pointer of the golang slice cannot be passed directly to the C function call. Instead, the header address and slice length of the internal buffer where the slice data is stored need to be taken out and passed:
Package main
/ *
# include
Static void fill_255 (char* buf, int32_t len) {
Int32_t i
For (I = 0; I)
< len; i++) { buf[i] = 255; } } */ import "C" import ( "fmt" "unsafe" ) func main() { b := make([]byte, 5) fmt.Println(b) // [0 0 0 0 0] C.fill_255((*C.char)(unsafe.Pointer(&b[0])), C.int32_t(len(b))) fmt.Println(b) // [255 255 255 255 255] } 字符串 golang 的字符串和 C 中的字符串在底层的内存模型也是不一样的: golang 字串符串并没有用 '\0' 终止符标识字符串的结束,因此直接将 golang 字符串底层数据指针传递给 C 函数是不行的。一种方案类似切片的传递一样将字符串数据指针和长度传递给 C 函数后,C 函数实现中自行申请一段内存拷贝字符串数据然后加上未层终止符后再使用。更好的方案是使用标准库提供的 C.CString() 将 golang 的字符串转换成 C 字符串然后传递给 C 函数调用: package main /* #include #include #include static char* cat(char* str1, char* str2) { static char buf[256]; strcpy(buf, str1); strcat(buf, str2); return buf; } */ import "C" import ( "fmt" "unsafe" ) func main() { str1, str2 := "hello", " world" // golang string ->C string
Cstr1, cstr2: = C.CString (str1), C.CString (str2)
Defer C.free (unsafe.Pointer (cstr1)) / / must call
Defer C.free (unsafe.Pointer (cstr2))
Cstr3: = C.cat (cstr1, cstr2)
/ / c string-> golang string
Str3: = C.GoString (cstr3)
Fmt.Println (str3) / / "hello world"
}
It should be noted that the C string returned by C.CString () is newly created on the heap and is not managed by GC. After using it, you need to call C.free () to release it, otherwise it will cause a memory leak, and this kind of memory leak cannot be located with the pprof described earlier.
Other types
Other types in golang (such as map) do not have an equivalent type or memory model is not the same in CAccord Category +. When passing, you need to understand the underlying memory model of the golang type, and then do a more elaborate memory copy operation. One way to pass map is to put all the key-value pairs of map into a slice, then pass the slice to the C++ function, and then restore the C++ function to the map of the C++ standard library. Since there are few scenarios to use, I will not repeat them here.
Summary
This article mainly introduces some of the details involved in using CGO to call the Candlestick + interface in golang. It needs to manage memory by itself because it is a low-level language. When using CGO, you need to have some understanding of the underlying memory model of golang. In addition, after goroutine enters the execution phase of the C interface through CGO, it has broken away from the scheduling of the golang runtime and monopolizes threads, which actually becomes the programming model of multi-thread synchronization. If there is a blocking operation in the C interface, it may cause all threads to be blocked, and other goroutine will not be scheduled, resulting in a much lower performance of the entire system. In general, you need to consider using CGO only if the third-party library does not have an implementation of golang and the cost of implementation is relatively high, otherwise you should use it with caution.
You can use go tool cgo to generate these stub files in the local directory
$go tool cgo main.go
.
| | _ obj |
| | _ cgo_.o |
| | _ cgo_export.c |
| | _ cgo_export.h |
| | _ cgo_flags |
| | _ cgo_gotypes.go |
| | _ cgo_main.c |
| | _ main.cgo1.go |
| | _ main.cgo2.c |
| | _ main.go |
Where main.cgo1.go is the main file, which is the file after the user code main.go has been rewritten by cgo:
$cat _ obj/main.cgo1.go
/ / Created by cgo-DO NOT EDIT
/ / line / Users/didi/goLang/src/github.com/xiazemin/cgo/exp1/main.go:1
Package main
/ / line / Users/didi/goLang/src/github.com/xiazemin/cgo/exp1/main.go:11
Import "fmt"
Func main () {
Var a, b int32 = 1,2
Var c int32 = int32 (_ Cfunc_add (_ Ctype_int32_t (a), _ Ctype_int32_t (b)
Fmt.Println (c)
}
This file is the user code that the compile component of Go actually sees. You can see that the import "C" in the original file is removed, while the user-written C.int is rewritten to _ Ctype_int,C.add3 and rewritten to _ Cfunc_add3. There are two points to note about this feature. First, in the file with import "C", all the user's comment information is lost, and some progma used are no exception. Second, import "C" is not allowed in the testing suite, which shows that testing does not support CGO. However, it is not impossible to use CGO in testing. You can take advantage of the above features to define the C function in a separate Go file and use import "C"; but you can use the _ Cfunc_add3 function directly in the Go file that uses testing. The _ Cfunc_add3 user does not display the definition, but CGO automatically generates the definition of this function. The above series of / / line compilation guidance statements are used to associate the generated Go with the line number information of the original user code.
Back to the _ Cfunc_add3 function again, it's not an add3 function in C, it's a Go function generated by CGO. It is defined in the pile file _ cgo_gotypes.go generated by CGO
$cat _ obj/_cgo_gotypes.go
/ / Created by cgo-DO NOT EDIT
Package main
Import "unsafe"
Import _ "runtime/cgo"
Import "syscall"
Var _ syscall.Errno
Func _ Cgo_ptr (ptr unsafe.Pointer) unsafe.Pointer {return ptr}
/ / go:linkname _ Cgo_always_false runtime.cgoAlwaysFalse
Var _ Cgo_always_false bool
/ / go:linkname _ Cgo_use runtime.cgoUse
Func _ Cgo_use (interface {})
Type_ Ctype_int int32
Type_ Ctype_int32_t _ Ctype_int
Type_ Ctype_void [0] byte
/ / go:linkname _ cgo_runtime_cgocall runtime.cgocall
Func _ cgo_runtime_cgocall (unsafe.Pointer, uintptr) int32
/ / go:linkname _ cgo_runtime_cgocallback runtime.cgocallback
Func _ cgo_runtime_cgocallback (unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
/ / go:linkname _ cgoCheckPointer runtime.cgoCheckPointer
Func _ cgoCheckPointer (interface {},... interface {})
/ / go:linkname _ cgoCheckResult runtime.cgoCheckResult
Func _ cgoCheckResult (interface {})
/ / go:cgo_import_static _ cgo_3a42ad434848_Cfunc_add
/ / go:linkname _ _ cgofn__cgo_3a42ad434848_Cfunc_add _ cgo_3a42ad434848_Cfunc_add
Var _ _ cgofn__cgo_3a42ad434848_Cfunc_add byte
Var _ cgo_3a42ad434848_Cfunc_add = unsafe.Pointer (& _ _ cgofn__cgo_3a42ad434848_Cfunc_add)
/ / go:cgo_unsafe_args
Func_ Cfunc_add (p0 _ Ctype_int32_t, p1 _ Ctype_int32_t) (R1 _ Ctype_int32_t) {
_ cgo_runtime_cgocall (_ cgo_3a42ad434848_Cfunc_add, uintptr (unsafe.Pointer (& p0)
If _ Cgo_always_false {
_ Cgo_use (p0)
_ Cgo_use (p1)
}
Return
}
The argument passing of _ Cfunc_add3 is somewhat different from that of a normal function in that its arguments are not on the stack, but on the heap. The _ Cgo_use in the function is actually runtime.cgoUse, which is used to tell the compiler to escape p0, p1, p2 to the heap, so that the parameters can be safely passed to the C program. (because go is dynamic stack unsafe)
$go build-gcflags "- m" main.go
# command-line-arguments
/ var/folders/r9/35q9g3d56_d9g0v59w9x2l9w0000gn/T/go-build789689150/command-line-arguments/_obj/_cgo_gotypes.go:14:6: can inline _ Cgo_ptr
/ var/folders/r9/35q9g3d56_d9g0v59w9x2l9w0000gn/T/go-build789689150/command-line-arguments/_obj/_cgo_gotypes.go:14:35: leaking param: ptr to result ~ R1 level=0
/ var/folders/r9/35q9g3d56_d9g0v59w9x2l9w0000gn/T/go-build789689150/command-line-arguments/_obj/_cgo_gotypes.go:27:6: _ cgo_runtime_cgocall assuming arg#2 is unsafe uintptr
/ var/folders/r9/35q9g3d56_d9g0v59w9x2l9w0000gn/T/go-build789689150/command-line-arguments/_obj/_cgo_gotypes.go:30:6: _ cgo_runtime_cgocallback assuming arg#3 is unsafe uintptr
/ var/folders/r9/35q9g3d56_d9g0v59w9x2l9w0000gn/T/go-build789689150/command-line-arguments/_obj/_cgo_gotypes.go:30:6: _ cgo_runtime_cgocallback assuming arg#4 is unsafe uintptr
/ var/folders/r9/35q9g3d56_d9g0v59w9x2l9w0000gn/T/go-build789689150/command-line-arguments/_obj/_cgo_gotypes.go:47:11: p0 escapes to heap
/ var/folders/r9/35q9g3d56_d9g0v59w9x2l9w0000gn/T/go-build789689150/command-line-arguments/_obj/_cgo_gotypes.go:48:11: p1 escapes to heap
/ var/folders/r9/35q9g3d56_d9g0v59w9x2l9w0000gn/T/go-build789689150/command-line-arguments/_obj/_cgo_gotypes.go:45:75: _ Cfunc_add & p0 does not escape
. / main.go:16: c escapes to heap
. / main.go:16: main... Argument does not escape
The _ _ cgo_79f22807c129_Cfunc_add3 in the function is a variable that records the address of a C function (note that this is not actually a call to the add3 function). It is a function that is really defined in the C program. In Go, get the address of the function _ _ cgo_79f22807c129_Cfunc_add3 in C when linking by compiling the guide statement / / go:cgo_import_static, and then align this function address with the address of the byte variable _ _ cgofn_cgo_79f22807c129_Cfunc_add3 in Go by compiling the guide statement / / go:linkname. Then a new variable _ _ cgo_79f22807c129_Cfunc_add3 is used to record the address of the byte variable. Thus, it is possible to get the address of the function in C in Go. After these are done, the function address and parameter address of C are passed to the cgocall function to perform the call ABI operation between Go and C. Of course, some preparatory actions related to scheduling will be done in cgocall, which will be explained in detail later.
_ _ cgo_79f22807c129_Cfunc_add3, as mentioned above, is a function defined in main.cgo2.c and is defined as follows:
CGO_NO_SANITIZE_THREAD
Void
_ cgo_3a42ad434848_Cfunc_add (void * v)
{
Struct {
Int32_t p0
Int32_t p1
Int32_t r
Char _ _ pad12 [4]
} _ _ attribute__ ((_ _ packed__)) * a = v
Char * stktop = _ cgo_topofstack ()
_ _ typeof__ (a-> r) r
_ cgo_tsan_acquire ()
R = add (a-> p0, a-> p1)
_ cgo_tsan_release ()
A = (void*) (char*) a + (_ cgo_topofstack ()-stktop))
A-> r = r
}
In the definition of this function, there is no explicit parameter copy; instead, the parameter address passed by Go is directly manipulated in C using type forcefulness. The user-defined add3 function is actually called in this function.
Cgocall, the _ cgo_runtime_cgocall function in _ Cfunc_add3, is a key function of calling C from Go to C in runtime. Some scheduling-related arrangements are made in this function. The reason for such a design is that after Go is transferred to C, the operation of the program is not controlled by Go's runtime. A normal Go function needs to be controlled by runtime, that is, too long running time of the function will lead to preemption of goroutine, and the execution of GC will cause all goroutine to be pulled together. The execution of C program restricts the scheduling behavior of Go's runtime. For this reason, the runtime of Go will mark the thread running C as excluded from the scheduling of runtime after entering the C program to reduce the impact of this thread on the scheduling of Go. In addition, because normal Go programs run on a 2K stack, C programs need an infinite stack. This design will cause the execution of the C function on the Go stack will cause the stack overflow, so before entering the C function, you need to switch the current thread's stack from the 2K stack to the thread's own system stack. Stack switching occurs in asmcgocall, while the status mark of a thread occurs in cgocall.
The above is all the content of the article "sample Analysis of cgo in golang". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.