Golang中大量goroutine导致cgo pthread互斥锁崩溃的问题
Golang中大量goroutine导致cgo pthread互斥锁崩溃的问题 这到底是怎么回事?我已经将ulimit增加到102400等等,但还是不行?!是Go语言有什么问题吗?
package main
/*
#include <pthread.h>
#include <stdlib.h>
pthread_mutex_t lock;
void lock_init() {
pthread_mutex_init(&lock, NULL);
}
void lock_destroy() {
pthread_mutex_destroy(&lock);
}
void lock_mutex() {
pthread_mutex_lock(&lock);
}
void unlock_mutex() {
pthread_mutex_unlock(&lock);
}
*/
import "C"
import (
// "runtime"
"sync"
"log"
"time"
)
func main() {
C.lock_init()
defer C.lock_destroy()
var wg sync.WaitGroup
for i := 0; i < 10000; i++ {
wg.Add(1)
go func() {
C.lock_mutex()
// Critical section: You can place code here that needs synchronization.
time.Sleep(300*time.Nanosecond)
C.unlock_mutex()
wg.Done()
}()
}
wg.Wait() // Wait for all goroutines to finish
log.Printf("same thing will crash in 3 second with more iterations")
time.Sleep(3*time.Second)
for i := 0; i < 1000000; i++ {
wg.Add(1)
go func() {
C.lock_mutex()
// Critical section: You can place code here that needs synchronization.
time.Sleep(300*time.Nanosecond)
C.unlock_mutex()
wg.Done()
}()
}
wg.Wait() // Wait for all goroutines to finish
}
更多关于Golang中大量goroutine导致cgo pthread互斥锁崩溃的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
不。你有任何可行的解决方案吗?
更多关于Golang中大量goroutine导致cgo pthread互斥锁崩溃的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
用于程序间的 Go 语言全局互斥锁锁定
这是如何工作的?
你能在 C 程序中使用 pthread_create 创建更多线程吗?
@Helmut_Wais 关于跨程序的 Go 全局互斥锁锁定。我将内核的 threads-max 设置为 1024000,但在 80000 个 goroutine 时仍然崩溃。如何解决?也尝试将 SetMaxThreads 设置为 1024000,但不起作用。崩溃。
为什么你使用 pthread_mutex_t 而不是 sync.Mutex?
仅仅是为了演示目的吗?
pthread_create 可能因其他原因而失败并返回 EAGAIN,而不仅仅是达到最大进程数。可能是内存或栈空间不足。
除了 ulimit -u 之外,其他限制也可能相关,例如 sysctl kernel.threads-max 或 sysctl vm.max_map_count。
并不是说我读过 Go 的源代码,但我可以想象,持有 pthread 互斥锁的线程上不会调度 goroutine。因此会不断创建新线程,直到 pthread_create 失败。
无论如何,创建 10 万或更多的 pthread 似乎是个坏主意。它们不像 goroutine 那样廉价。
// 代码示例(如果原内容包含)
// 此处应放置原HTML中的Go代码,但当前提供的HTML片段未包含具体的Go代码块。
// 根据要求,所有Go代码必须用```go包裹。
这是典型的Go调度器与C线程互斥锁交互问题。Go的goroutine在C调用期间可能被调度到不同的OS线程,而pthread互斥锁要求加锁和解锁必须在同一线程中执行。
问题分析:
- 当goroutine在C.lock_mutex()调用后被调度到另一个OS线程时
- 后续的C.unlock_mutex()可能在不同线程中执行,违反pthread互斥锁要求
- 大量goroutine加剧了线程迁移的可能性
解决方案:使用runtime.LockOSThread()将goroutine绑定到当前OS线程
package main
/*
#include <pthread.h>
#include <stdlib.h>
pthread_mutex_t lock;
void lock_init() {
pthread_mutex_init(&lock, NULL);
}
void lock_destroy() {
pthread_mutex_destroy(&lock);
}
void lock_mutex() {
pthread_mutex_lock(&lock);
}
void unlock_mutex() {
pthread_mutex_unlock(&lock);
}
*/
import "C"
import (
"runtime"
"sync"
"log"
"time"
)
func worker(wg *sync.WaitGroup) {
runtime.LockOSThread() // 绑定goroutine到当前OS线程
defer runtime.UnlockOSThread()
C.lock_mutex()
time.Sleep(300*time.Nanosecond)
C.unlock_mutex()
wg.Done()
}
func main() {
C.lock_init()
defer C.lock_destroy()
var wg sync.WaitGroup
// 第一轮测试
for i := 0; i < 10000; i++ {
wg.Add(1)
go worker(&wg)
}
wg.Wait()
log.Printf("使用LockOSThread后,第二轮测试不会崩溃")
time.Sleep(3*time.Second)
// 第二轮测试
for i := 0; i < 1000000; i++ {
wg.Add(1)
go worker(&wg)
}
wg.Wait()
log.Printf("所有goroutine执行完成")
}
替代方案:使用Go原生的sync.Mutex(推荐)
package main
import (
"sync"
"log"
"time"
)
func main() {
var mu sync.Mutex
var wg sync.WaitGroup
// 第一轮测试
for i := 0; i < 10000; i++ {
wg.Add(1)
go func() {
mu.Lock()
time.Sleep(300*time.Nanosecond)
mu.Unlock()
wg.Done()
}()
}
wg.Wait()
log.Printf("使用sync.Mutex,第二轮测试不会崩溃")
time.Sleep(3*time.Second)
// 第二轮测试
for i := 0; i < 1000000; i++ {
wg.Add(1)
go func() {
mu.Lock()
time.Sleep(300*time.Nanosecond)
mu.Unlock()
wg.Done()
}()
}
wg.Wait()
log.Printf("所有goroutine执行完成")
}
关键点:
- Go调度器可能在任何函数调用点切换goroutine到不同OS线程
- pthread互斥锁有线程关联性要求
- runtime.LockOSThread()确保C调用在同一线程中执行
- 优先使用Go原生同步原语,避免cgo线程安全问题

