亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

cgo 與使用線程本地存儲的 C 庫交互

cgo 與使用線程本地存儲的 C 庫交互

Go
神不在的星期二 2022-06-01 12:21:06
我正在用 cgo 包裝一個 C 庫以供普通 Go 代碼使用。我的問題是我想將錯誤字符串傳播到 Go API,但是有問題的 C 庫通過線程本地存儲提供錯誤字符串;有一個全局get_error()調用返回指向線程本地字符數據的指針。我最初的計劃是通過 cgo 調用 C,檢查調用是否返回錯誤,如果是,則將錯誤字符串包裝起來C.GoString,將其從原始字符指針轉換為 Go 字符串。它看起來像C.GoString(C.get_error()).我在這里預見到的問題是 C 中的 TLS 在本機 OS 線程級別上工作,但據我了解,調用 Go 代碼將來自潛在的 N 個 goroutine 之一,這些 goroutine 在某個數量的底層本地線程中多路復用由 Go 調度程序管理的線程池。我害怕遇到這樣一種情況:我調用了 C 例程,然后在 C 例程返回之后,但在我復制錯誤字符串之前,Go 調度程序決定將當前的 goroutine 換成另一個。當原始的 goroutine 被換回時,據我所知,它可能位于不同的本地線程上,但即使它被換回同一個線程,在此期間運行的任何 goroutine 都可能改變了狀態的 TLS,導致我為不相關的調用加載錯誤字符串。我的問題是:這是一個合理的擔憂嗎?我是否誤解了 go 調度程序,或者它與 cgo 交互的方式,這會導致這不是問題?如果這是一個合理的問題,我該如何解決?cgo 設法將 errno 值傳播回調用 Go 代碼,這些代碼也存儲在 TLS 中,這讓我認為必須有一種安全的方法來做到這一點。我想不出 C 代碼本身可以被 go 調度程序搶占的方式,所以我應該引入一個包裝 C 函數并讓 IT 進行必要的調用,然后在返回 goland 之前有條件地復制錯誤字符串?我對任何允許我將錯誤字符串傳播到 Go 的其余部分的解決方案感興趣,但我希望避免任何需要我序列化圍繞 TLS 的訪問的解決方案,因為添加一個鎖只是為了抓取一個錯誤字符串對我來說似乎非常不幸。提前致謝!
查看完整描述

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.


查看完整回答
反對 回復 2022-06-01
  • 1 回答
  • 0 關注
  • 159 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號