2012-10-03 14 views
8

Tiêu chuẩn cho biết: "Một đối tượng của loại chuỗi :: id cung cấp ... một giá trị riêng biệt duy nhất cho tất cả các đối tượng chuỗi không đại diện cho một chuỗi thực thi". Đó có phải là giá trị đơn/riêng biệt liên quan đến operator== hay là giá trị bit/đơn lẻ thực tế?Yêu cầu đối với std :: thread :: id. Nó có thể được phun không?

Lý do cho câu hỏi: std::thread::id::id() của MSVC2012 để rác trong một trong các trường của nó và mã ngắt mã so sánh trên std::atomic<std::thread::id> (vì sau này phụ thuộc vào so sánh bitwise).

Có phải là std::atomic<std::thread::id> một cấu trúc pháp lý ngay từ đầu không?

EDIT: cho tài liệu tham khảo, các mã đi như thế này:

while(!worker_id.compare_exchange_weak(no_id = thread_id_type(), self_id)) 
    sleep(); 

Trả lời

10

Thứ nhất, std::atomic<std::thread::id> là hợp pháp: Yêu cầu std::thread::id để có thể sao chép một cách trivially (30.3.1.1p2), đáp ứng các yêu cầu của std::atomic<> (29.5p1).

Tuy nhiên, đây là một lớp mờ, vì vậy không có yêu cầu rằng mẫu bit của các đối tượng so sánh bằng nhau giống hệt nhau.

Do đó, nếu bạn sử dụng compare_exchange_weak hoặc compare_exchange_strong thì có thể không thành công cho các giá trị so sánh bằng nhau.

Do đó, lời khuyên là sử dụng compare_exchange_weak trong vòng lặp, để giá trị expected là kết quả của lần lặp trước.

Trong trường hợp của bạn, ngữ nghĩa tôi giải thích từ vòng lặp của bạn là: giữ vòng lặp trong khi worker_id là ID của một chủ đề khác hoặc worker_idstd::thread::id nhưng trao đổi không thành công. Bạn có thể đạt được điều này như sau:

no_id=std::thread::id(); 
while((no_id!=std::thread::id()) || 
     !worker_id.compare_exchange_weak(no_id, self_id)){ 
    if(no_id!=std::thread::id()) no_id=std::thread::id(); 
    sleep(); 
} 

hoặc

no_id=std::thread::id(); 
while(!worker_id.compare_exchange_weak(
      (no_id!=std::thread::id())?(no_id=std::thread::id())?no_id, self_id)) 
    sleep(); 

ví dụ: chỉ thay đổi giá trị no_id nếu nó là khôngstd::thread::id().

+0

Cảm ơn bạn.Chọn lọc đặt lại 'no_id' là một mẹo hay, bây giờ tôi bắt đầu tự hỏi tại sao tôi không thấy nó :) – vpozdyayev

+0

Nhưng bạn có thể chỉ muốn gọi ngủ nếu" no_id! = Std :: thread :: id() " trong vòng. – cmeerw

+0

@cmeerw Vâng --- Tôi đã cố gắng sao chép vòng lặp của vpozdyayev càng chặt chẽ càng tốt. Nếu 'compare_exchange_weak' thất bại" giả "thì bạn trong hầu hết các trường hợp bạn muốn lặp lại ngay lập tức, mà không cần chờ đợi. –

5

này đã được thảo luận trong LWG924. Về cơ bản, bạn không thể sử dụng compare_exchange_strong, nhưng bạn sẽ có thể sử dụng compare_exchange_weak trong một vòng lặp, ví dụ:

expected = current.load(); 
do { 
    desired = function(expected); 
} while (!current.compare_exchange_weak(expected, desired)); 

Sửa: Unconditionally đặt lại giá trị đánh bại mục đích của loop - dựa trên mã được cung cấp, tôi nghĩ rằng giải pháp tốt nhất sau đó sẽ là:

no_id = std::thread::id(); 
while(!worker_id.compare_exchange_weak(no_id, self_id)) 
{ 
    if (no_id != std::thread::id()) 
    { 
    sleep(); 
    no_id = std::thread::id(); 
    } 
} 
+0

Tôi đang sử dụng 'compare_exchange_weak' trong một vòng lặp và thật đáng buồn là nó không giúp ích gì. BTW, vấn đề ở đây là uninitialized lĩnh vực, không đệm (được đề cập như là một "liên quan nhưng tách vấn đề" trong liên kết của bạn). Tôi nhận thấy ghi chú 29.6.5/26 về ngữ nghĩa memcmp và compare_exchange_weak hội tụ nhanh, nhưng tôi vẫn không thấy nó có thể hoạt động như thế nào nếu 'current' và' expected' là các biểu diễn khác nhau của bit giống nhau (như mỗi giá trị 'operator =='). – vpozdyayev

+0

Đã thêm mẫu mã vào câu hỏi. – vpozdyayev