問題:
所以我對 CPP 很陌生,我試圖使用一些原子性概念來實作一個簡單的比較代碼。
問題是我沒有得到想要的結果,即:即使 compare_exchange_strong 函式更新了原子變數 ( std::atomic) 的值,它也回傳 false。
下面是程式代碼:
共產黨:
Action::Action(Type type, Transfer *transfer)
: transfer(transfer),
type(type) {
Internal = 0;
InternalHigh = -1;
Offset = OffsetHigh = 0;
hEvent = NULL;
status = Action::Status::PENDING;
}
BOOL CancelTimeout(OnTimeoutCallback* rt)
{
auto expected = App::Action::Status::PENDING;
if (rt->action->status.compare_exchange_strong(expected, App::Action::Status::CANCEL))
{
CancelWaitableTimer(rt->hTimer);
return true;
}
return false;
}
標題:
struct Action : OVERLAPPED {
enum class Type : long {
SEND,
RECEIVE
};
enum class Status : long {
PENDING,
CANCEL,
TIMEOUT
};
atomic<Status> status;
Transfer *transfer = NULL;
Type type;
WSABUF *data = NULL;
OnTimeoutCallback *timeoutCallback;
Action(Type type, Transfer *transfer);
~Action();
}
復查,變數的值rt->action->status更新為Action::Status::CANCEL列舉,但是compare_exchange_strong函式的回傳為 false。
在除錯中查看問題:

也就是說,考慮到它改變了變數的值,期望的結果是觸發第一個斷點,即回傳 true,而不是回傳 false。
更新:在列印中我意外洗掉了第一個斷點,但我認為這是可以理解的
已經嘗試過
- 修改結構為:
enum class Status : long - 修改結構為:
enum class Status : size_t - 修改所有結構項的位置
已經搜索過類似主題
[但沒有成功]
| 關聯 | 搜索詞 |
|---|---|
| 為什么 compare_exchange_strong 在 C 中因 std::atomic<double>, std::atomic<float> 而失敗? | compare_exchange_strong 失敗 |
| cpp compare_exchange_strong 虛假失敗? | 比較交換失敗 |
| 不要真正理解 std::atomic::compare_exchange_weak 和 compare_exchange_strong 的邏輯 | std::atomic::compare_exchange_weak 和 compare_exchange_strong |
| C 14 是否在 unsigned int 的填充位上定義位運算子的行為? | 填充問題比較交換 |
在具有不同搜索詞的其他幾個主題中
重要說明
- 代碼是多執行緒的
- 代碼中沒有其他地方將原子變數的值更新為列舉
Action::Status::CANCEL - 我懷疑這與填充有關(由于一些谷歌搜索),但由于我是 CPP 的新手,我不知道如何修改我的框架來解決問題
- 每次請求都會生成一個新的 Action 結構實體,并且我還確保不會在同一個指標 (Action*) 上發生并發,因為每次更改都會生成一個新的 Action 結構實體
等待!
值得一提的是,我正在使用谷歌翻譯發布這個問題,以防有什么不對,如果我的問題不完整,或者格式不合適,請評論以便我調整,提前謝謝你,
盧卡斯P。
更新:
我無法使用代碼的縮小版本來復制問題,也就是說,我必須發布整個解決方案(這已經非常小,因為它是一個研究專案):
https://drive.google.com/file/d/13fP7OUCC6GeMgUtrPHSOnSGUEBwDGqBC/view?usp=sharing
uj5u.com熱心網友回復:
TL:DR:另一個執行緒修改它與除錯器獲得控制和讀取被除錯行程的記憶體之間的競爭條件。
或者該值已經存在Action::Status::CANCEL很長時間,not expected = App::Action::Status::PENDING;,在這種情況下,單獨運行的單個執行緒可能會出現這種行為。我假設您的程式僅在兩個執行緒嘗試同時執行此操作時才期望此 CAS 失敗,例如僅在有待處理的情況下才首先呼叫此函式。
我假設有另一個執行緒可以CancelTimeout同時呼叫,否則你不需要原子 RMW。 (如果這是修改它的唯一執行緒,您只需檢查該值,并在手動比較之后對新值進行純存盤,例如.store(CANCEL),可能使用 std::memory_order_release 或放松。)
這將解釋您的觀察結果:
另一個執行緒贏得了 modify 的競賽
rt->action->status,因此它的 CAS 回傳 true。CAS_strong在這個執行緒中沒有修改變數,并回傳false。這個執行緒中的
if主體沒有運行,所以這個執行緒命中了你的斷點。在除錯器最終獲得控制權并且行程的所有執行緒都暫停后,除錯器要求內核讀取被除錯行程的記憶體。由于我們的 CAS 失敗了,其他執行緒的更新
rt->action->status肯定已經發生了,所以除錯器會看到。(特別是在除錯器獲得控制所需的所有時間之后,塵埃將有時間解決。但假設您使用的是 x86 或 ARMv8,那么在一個執行緒中的存盤對任何其他執行緒都是可見的,這意味著它們是全域可見的, 到所有執行緒;這些 ISA 是多副本原子的,沒有 IRIW 重新排序。)
所以 CAS 失敗正是因為其他一些執行緒已經改變了這個值。CAS失敗的執行緒沒有改變它。 無論 CAS 之前或之后的值如何,只要 CAS 失敗,您的斷點就會觸發。
要使 CAS_strong 實際回傳 false 并更新值,您的編譯器或 CPU 必須有問題。這些都是可能的(尤其是編譯器錯誤),但是是非常特殊的宣告,需要非常仔細地排除相同觀察結果的軟體原因。當您還沒有理清所有細節并且不確定您是否了解正在發生的一切時,這絕不應該是您的第一個猜測。
如果您認為原始操作沒有按照檔案所說的那樣做,那么它實際上幾乎總是在其他地方存在錯誤,或者缺少對您所看到的內容的一些可能的解釋,而這些解釋不需要編譯器錯誤來解釋。
可以向 Stack Overflow 提問關于發生了什么的問題,但請記住,在撰寫標題時,您的 C 編譯器實際上不太可能損壞。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/515411.html
上一篇:如何附加遠程java除錯器來除錯rundeck插件?
下一篇:2個鍵的陣列中的未定義鍵1
