1 回答

TA貢獻1995條經驗 獲得超2個贊
害怕遇到這樣一種情況:我調用了 C 例程,然后在 C 例程返回之后,但在我復制錯誤字符串之前,Go 調度程序決定將當前的 goroutine 換成另一個。...
這是一個合理的擔憂嗎?
是的。cgo“調用 C 代碼”包裝器在每次調用期間鎖定一個 POSIX / OS 線程,但它們鎖定的線程并非一直固定;實際上,只要您的 goroutine 正常運行,它確實會隨著時間的推移跳轉到多個不同的線程。(由于 Go 在當前實現中是協作調度的,在某些情況下,您可以小心不要做任何可能讓您切換底層操作系統線程的事情,但這可能不是一個好計劃。)
你可以在這里使用runtime.LockOSThread,但我認為最好的計劃是:
我該如何解決?
在Go 恢復其正常的調度算法之前(即,在從 C/POSIX 線程解鎖 goroutine 之前)獲取錯誤。
cgo 以某種方式設法傳播 errno 值...
它在從 POSIX 線程解鎖 goroutine之前獲取 errno 值。
我最初的計劃是通過 cgo 調用 C,檢查調用是否返回錯誤,如果是,則將錯誤字符串包裝起來C.GoString,將其從原始字符指針轉換為 Go 字符串。它看起來像C.GoString(C.get_error()).
如果有這樣的變體獲取錯誤號(而不是將其從 TLS 變量中取出),那么該計劃應該仍然有效:只需確保您的 C 例程提供返回值和錯誤號即可。
如果沒有,請按照您的建議編寫自己的 C 包裝器:
ftype wrapper_for_realfunc(char **errp, arg1type arg1, arg2type arg2) {
ftype ret = realfunc(arg1, arg2);
if IS_ERROR(ret) {
*errp = get_error();
} else {
*errp = NULL;
}
return ret;
}
現在你的 Go 包裝器簡單地調用包裝器,它用一個額外的參數填充指向 C 內存的指針,*C.char如果沒有錯誤,則將其設置為 nil,如果有錯誤,則將其設置為可以使用的東西C.GoString。
如果由于某種原因這不可行,請考慮使用runtime.LockOSThread及其對應的runtime.UnlockOSThread.
- 1 回答
- 0 關注
- 159 瀏覽
添加回答
舉報