2009-05-16 41 views
5

Tôi có một câu hỏi khá cụ thể về lập trình đồng thời trong C. Tôi đã thực hiện một chút công bằng về nghiên cứu này nhưng đã thấy một số câu trả lời mâu thuẫn, vì vậy tôi hy vọng cho một số làm rõ. Tôi có một chương trình đó là một cái gì đó như sau (xin lỗi vì khối mã hơi dài):truy cập biến đồng thời trong c

typedef struct { 
    pthread_mutex_t mutex; 
    /* some shared data */ 
    int eventCounter; 
} SharedData; 

SharedData globalSharedData; 

typedef struct { 
    /* details unimportant */ 
} NewData; 

void newData(NewData data) { 
    int localCopyOfCounter; 

    if (/* information contained in new data triggers an 
     event */) { 
    pthread_mutex_lock(&globalSharedData.mutex); 
    localCopyOfCounter = ++globalSharedData.eventCounter; 
    pthread_mutex_unlock(&globalSharedData.mutex); 
    } 
    else { 
    return; 
    } 

    /* Perform long running computation. */ 

    if (localCopyOfCounter != globalSharedData.eventCounter) { 
    /* A new event has happened, old information is stale and 
     the current computation can be aborted. */ 
    return; 
    } 

    /* Perform another long running computation whose results 
    depend on the previous one. */ 

    if (localCopyOfCounter != globalSharedData.eventCounter) { 
    /* Another check for new event that causes information 
     to be stale. */ 
    return; 
    } 

    /* Final stage of computation whose results depend on two 
    previous stages. */ 
} 

Có một thread pool phục vụ kết nối dữ liệu đến, vì vậy nhiều trường hợp của newData có thể chạy cùng một lúc . Trong môi trường đa bộ xử lý có hai vấn đề mà tôi nhận thấy trong việc xử lý bộ phận xử lý truy cập của mã này chính xác: ngăn trình biên dịch lưu vào bộ nhớ cache bản sao được chia sẻ trong sổ đăng ký để các chủ đề khác không thể nhìn thấy và buộc CPU để ghi lưu trữ giá trị bộ đếm vào bộ nhớ một cách kịp thời để các luồng khác có thể nhìn thấy nó. Tôi không muốn sử dụng một cuộc gọi đồng bộ xung quanh kiểm tra bộ đếm vì một phần đọc của giá trị bộ đếm được chấp nhận (nó sẽ tạo ra một giá trị khác với bản sao cục bộ, đủ để kết luận rằng một sự kiện đã xảy ra). Nó sẽ là đủ để khai báo các lĩnh vực eventCounter trong SharedData là dễ bay hơi, hoặc tôi cần phải làm cái gì khác ở đây? Ngoài ra là có một cách tốt hơn để xử lý này?

Trả lời

2

Thật không may, tiêu chuẩn C cho biết rất ít về đồng thời. Tuy nhiên, hầu hết các trình biên dịch (gcc và msvc, anyway) sẽ coi một biến động dễ bay hơi như thể có acquire semantics - biến dễ bay hơi sẽ được tải lại từ bộ nhớ trên mọi truy cập. Đó là mong muốn, mã của bạn như nó bây giờ có thể kết thúc so sánh các giá trị được lưu trữ trong sổ đăng ký. Tôi thậm chí sẽ không ngạc nhiên nếu cả hai so sánh đều được tối ưu hóa.

Vì vậy, câu trả lời là có, làm cho eventCounter dễ bay hơi. Ngoài ra, nếu bạn không muốn giới hạn trình biên dịch quá nhiều, bạn có thể sử dụng chức năng sau để thực hiện các lần đọc eventCounter.

int load_acquire(volatile int * counter) { return *counter; } 

if (localCopy != load_acquire(&sharedCopy)) 
    // ... 
0

ngăn chặn các trình biên dịch từ bộ nhớ đệm bản sao truy cập địa phương trong một thanh ghi đề rất khác không thể nhìn thấy nó

copy truy cập địa phương của bạn là "địa phương", tạo ra tình hình thực hiện ngăn xếp và chỉ hiển thị với chuỗi đang chạy. Mỗi luồng khác chạy trong một ngăn xếp khác nhau và có biến truy cập cục bộ riêng (không có sự tương tranh).

Bộ đếm toàn cầu của bạn nên được khai báo dễ bay hơi để tránh tối ưu hóa đăng ký.

+0

Bạn hoàn toàn chính xác về bản sao cục bộ, tôi vừa sửa lỗi đó trong văn bản của mình. – user98166

0

Bạn cũng có thể sử dụng bộ mã hóa hoặc trình biên dịch được mã hóa bằng tay intrinsics sẽ kiểm tra nguyên tử đối với mutex của bạn, chúng cũng có thể ++ và - bộ đếm của bạn.

dễ bay hơi là useless những ngày này, hầu hết các phần, bạn nên xem xét rào cản bộ nhớ là cơ sở CPU cấp thấp khác để trợ giúp với sự tranh chấp đa lõi.

Tuy nhiên, lời khuyên tốt nhất mà tôi có thể đưa ra, là để bạn có thể tập trung vào các thư viện hỗ trợ đa lõi được quản lý và bản địa khác nhau. Tôi đoán một số người lớn tuổi như OpenMP hoặc MPI (tin nhắn dựa), vẫn đang đá và mọi người sẽ tiếp tục về mức độ tuyệt vời của họ ... tuy nhiên đối với hầu hết các nhà phát triển, chẳng hạn như intel's TBB hoặc Microsoft's API mới, tôi cũng chỉ đào lập dự án mã này article, anh ấy rõ ràng đang sử dụng cmpxchg8b là tuyến đường phần cứng lowlevel mà tôi đã đề cập ban đầu ...

Chúc may mắn.

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