Tôi đã viết một chương trình Windows bằng C++ mà đôi khi sử dụng hai luồng: một luồng nền để thực hiện công việc tốn thời gian; và một chủ đề khác để quản lý giao diện đồ họa. Bằng cách này, chương trình vẫn đáp ứng với người dùng, điều này là cần thiết để có thể hủy bỏ một hoạt động nhất định. Các chủ đề giao tiếp thông qua biến số bool
được chia sẻ, được đặt thành true
khi chuỗi GUI báo hiệu chuỗi công nhân bị hủy. Đây là mã mà thực hiện hành vi này (tôi đã bị tước đi phần không liên quan):Có phải 'biến động' cần thiết trong mã C++ đa luồng này không?
mã thực thi bởi các thread GUI
class ProgressBarDialog : protected Dialog {
/**
* This points to the variable which the worker thread reads to check if it
* should abort or not.
*/
bool volatile* threadParameterAbort_;
...
BOOL CALLBACK ProgressBarDialog::DialogProc(HWND dialog, UINT message,
WPARAM wParam, LPARAM lParam) {
switch(message) {
case WM_COMMAND :
switch (LOWORD(wParam)) {
...
case IDCANCEL :
case IDC_BUTTON_CANCEL :
switch (progressMode_) {
if (confirmAbort()) {
// This causes the worker thread to be aborted
*threadParameterAbort_ = true;
}
break;
}
return TRUE;
}
}
return FALSE;
}
...
};
MÃ thực hiện bởi CÔNG NHÂN THREAD
class CsvFileHandler {
/**
* This points to the variable which is set by the GUI thread when this
* thread should abort its execution.
*/
bool volatile* threadParamAbort_;
...
ParseResult parseFile(ItemList* list) {
ParseResult result;
...
while (readLine(&line)) {
if ((threadParamAbort_ != NULL) && *threadParamAbort_) {
break;
}
...
}
return result;
}
...
};
threadParameterAbort_
trong cả hai luồng đều trỏ đến biến số bool
được khai báo trong cấu trúc được chuyển đến chuỗi công nhân khi tạo. Nó được khai báo là
bool volatile abortExecution_;
Câu hỏi của tôi là: sao tôi cần phải sử dụng volatile
ở đây, và là mã trên đủ để đảm bảo rằng chương trình là thread-an toàn không? Con đường tôi đã lập luận để biện minh cho việc sử dụng các volatile
đây (xem this question cho nền) là nó sẽ:
ngăn chặn việc đọc
*threadParameterAbort_
sử dụng bộ nhớ cache và thay vào đó lấy giá trị từ bộ nhớ, vàngăn trình biên dịch xóa mệnh đề
if
trong chuỗi công việc do tối ưu hóa.
(Đoạn sau đây là chỉ quan tâm đến các chủ đề an toàn của chương trình như vậy và không, tôi lặp lại, không liên quan đến tuyên bố rằng volatile
dưới mọi hình thức cung cấp bất kỳ phương tiện đảm bảo chủ đề -Safety như tôi có thể nói, nó nên được thread-an toàn như thiết lập của một biến bool
nên trong hầu hết, nếu không phải tất cả, kiến trúc là một hoạt động nguyên tử. Nhưng tôi có thể sai. Và tôi cũng lo lắng về việc trình biên dịch có thể sắp xếp lại các hướng dẫn như phá vỡ an toàn luồng không. Nhưng tốt hơn là an toàn (không có ý định chơi chữ) hơn là xin lỗi.
CHỈNH SỬA: Một lỗi nhỏ trong từ ngữ của tôi khiến câu hỏi xuất hiện như thể tôi hỏi nếu volatile
đủ để đảm bảo an toàn cho luồng. Đây không phải là ý định của tôi - volatile
thực sự không đảm bảo an toàn luồng theo bất kỳ cách nào - nhưng điều tôi muốn hỏi là nếu mã được cung cấp ở trên thể hiện hành vi đúng để đảm bảo chương trình an toàn chỉ.
Ghẻ tốt hơn [một nửa số đó] (http://stackoverflow.com/search?q=c%2B%2B+thread+volatile). IIRC gần đây nhất là [câu hỏi] (http://stackoverflow.com/questions/3372703/volatile-and-multithreading). – Dummy00001
Câu hỏi ngày hôm qua từ cùng một người bao gồm cùng một nền tảng: http://stackoverflow.com/questions/3604569/what-kinds-of-optimizations-does-volatile-prevent-in-c. Nếu bạn không viết một trình điều khiển thiết bị và bạn không quen thuộc với trình biên dịch, bạn không cần 'biến động'. – Potatoswatter
@Potatoswatter: Nhưng có vẻ như 'biến động' có thể được sử dụng khi viết mã đa luồng, như được hiển thị trong bài viết này (http://www.drdobbs.com/cpp/184403766) được liên kết trong một trong các câu trả lời. – gablin