2009-12-28 31 views
5

Một câu hỏi ngày hôm qua về khóa đã kiểm tra gấp đôi đã bắt đầu một chuỗi suy nghĩ khiến tôi không chắc chắn về một tình huống đơn giản. Trong đoạn mã sau, có thể nhấn printf của “Không còn đồng bộ hóa” nữa không? Trong ví dụ đơn giản này, các giá trị có thể nằm trên cùng một dòng bộ nhớ cache, vì vậy tôi nghĩ rằng nó sẽ ít có khả năng hơn (giả sử khả năng là> 0% để bắt đầu với).WaitForSingleObject có phục vụ như một rào cản bộ nhớ không?

Nếu câu trả lời là "Không, không thể.", Thì câu hỏi tiếp theo của tôi là, thay vì dự đoán được: tại sao không? Cho đến khi tôi nhận được suy nghĩ của tôi rối và quấn quanh trục đa luồng ngày hôm qua, tôi giả định rằng mã sẽ được an toàn. Nhưng bây giờ tôi tự hỏi những gì ngăn cản một đọc cũ từ bộ nhớ cache cho một trong các biến pa hoặc pb. Và liệu nó có quan trọng nếu pa, pb trỏ đến các biến số nguyên đơn giản toàn cầu thay vì bộ nhớ malloc’d? Cuộc gọi WaitForSingleObject có cung cấp rào cản bộ nhớ không? Hay các con trỏ nên được khai báo dễ bay hơi? Rất nhiều câu hỏi, rất ít câu.

Cập nhật: Cuối cùng tôi đã tìm thông tin cụ thể cho biết các chức năng mà các đối tượng đồng bộ hóa tín hiệu sử dụng memory barriers. Nó phải có được rõ ràng, nhưng tôi đã gặp khó khăn khi tìm một câu trả lời dứt khoát. Vì vậy, tôi có thể một lần nữa tự lừa dối bản thân mình để tin rằng tôi hiểu tất cả.

int i1 = 0; 
int i2 = 0; 
int reads = 0; 
int done = 0; 
int *pa = NULL; 
int *pb = NULL; 
HANDLE hSync = NULL; 

DWORD WriteThread(LPVOID pvParam) 
{ 
    while(!done) 
     { 
     WaitForSingleObject(hSync, INFINITE); 
     (*pa)++; 
     (*pb)++; 
     ReleaseSemaphore(hSync, 1, NULL); 
     } 
    return 0; 
} 

DWORD ReadThread(LPVOID pvParam) 
{ 
    while(!done) 
     { 
     WaitForSingleObject(hSync, INFINITE); 
     if (*pa != *pb) 
     { 
     printf("No longer in sync: %d, %d\n", *pa, *pb); 
     exit(1); 
     } 
     ReleaseSemaphore(hSync, 1, NULL); 
     reads++; 
     } 
    return 0; 
} 

int main(int argc, char* argv[]) 
{ 
    DWORD dwID; 

    // malloc'd memory 
    pa = (int*)malloc(sizeof(int)); 
    pb = (int*)malloc(sizeof(int)); 

    // Is a simple global variable different? 
    //pa = &i1; 
    //pb = &i2; 

    *pa = 0; 
    *pb = 0; 

    hSync = CreateSemaphore(NULL, 1, 1, NULL); 
    CreateThread(NULL, 0, WriteThread, NULL, 0, &dwID); 
    CreateThread(NULL, 0, ReadThread, NULL, 0, &dwID); 

    while (*pa < 1000000) 
     Sleep(1); 
    done = 1; 

    return 0; 
} 

Trả lời

4

Không quan trọng bộ nhớ nằm ở đâu và nếu tất cả là về sự kết hợp bộ nhớ cache thì việc khai báo biến sẽ không làm gì để khắc phục. Các ngữ nghĩa của Volatile không cần thiết và cũng không đủ cho thread-safety; không sử dụng nó!

Ở cấp C/C++, pa và pb có thể được lưu trong bộ đệm, nhưng chúng sẽ được coi là cũ sau khi có bất kỳ cuộc gọi chức năng nào. Ở cấp độ CPU, tất cả các chức năng chờ sử dụng các rào cản để đảm bảo mọi thứ hoạt động như mong đợi.

+0

+1 chính xác những gì tôi định nói. – tony

+0

Cảm ơn bạn đã cung cấp thông tin. Bạn có biết một liên kết thảo luận về các chức năng chờ đợi và các rào cản bộ nhớ. Đó là những gì tôi đang tìm kiếm và không nhìn thấy nó. Nó khá có thể tôi chỉ mù và bỏ lỡ một cái gì đó hiển nhiên. –

+2

Bạn không mù; rất khó để tìm thấy thông tin liên quan trực tuyến. MSDN cung cấp một cái nhìn tổng quan hợp lý tại http://msdn.microsoft.com/en-us/library/ms686355%28VS.85%29.aspx. –

Các vấn đề liên quan