2017-05-31 10 views
5

Giả sử tôi có một lớp học có chứa std::atomic_flag là thành viên riêng tư, được hiển thị thông qua bộ nạp. Giống như sau (pseudo-code):Không gói một std :: atomic_flag trong một getter/setter void "atomicity" của nó?

class Thing 
{ 
private: 

    std::atomic_flag ready = ATOMIC_FLAG_INIT; 

public: 

    isReady() 
    { 
     return ready.test_and_set(); 
    } 
} 

câu hỏi ngây thơ của tôi là: không truy vấn cờ thông qua một phương pháp biến nó thành một hoạt động phi nguyên tử, là một lời gọi hàm phi nguyên tử (hoặc là nó?)? Tôi có nên đặt cờ ready thành viên công khai của mình và truy vấn trực tiếp không?

+3

Truy cập và truy cập trực tiếp bằng cuộc gọi hàm không ảnh hưởng đến bản chất nguyên tử của 'ready'. Bạn có thể nói làm thế nào bạn sử dụng 'ready' như tôi nghi ngờ điều này có thể là vấn đề thực sự? –

+0

@RichardCritten Tôi giả sử (tôi chỉ là một sự tò mò, không phải là một chương trình thực sự) một luồng khác có thể lấy trạng thái sẵn sàng của Thing bằng cách lặp qua 'isReady', như' while (! IsReady()) do_something() '. Nó có ý nghĩa không? – Ignorant

Trả lời

6

Không, không. Các hoạt động test_and_set() chính nó là nguyên tử, do đó, nó không quan trọng như thế nào sâu chủ đề khác nhau 'ngăn xếp được ngăn xếp.

Để chứng minh điều này, hãy xem xét các trường hợp cơ sở nơi đối tượng atomic_flag được "tiếp xúc" trực tiếp:

static atomic_flag flag = ATOMIC_FLAG_INIT; 

void threadMethod() { 

    bool wasFirst = !flag.test_and_set(); 
    if(wasFirst) cout << "I am thread " << this_thread::get_id() << ", I was first!"  << endl; 
    else   cout << "I am thread " << this_thread::get_id() << ", I'm the runner-up" << endl; 
} 

Nếu hai luồng nhập threadMethod - với một thread (t1) hơi trước kia (t2) sau đó chúng tôi có thể mong đợi giao diện điều khiển đầu ra được những điều sau đây (theo thứ tự):

I am thread t1, I was first! 
I am thread t2, I'm the runner-up 

Bây giờ nếu cả hai đề nhập cùng một lúc, nhưng t2 là một microseco nd trước t1, nhưng t2 sau đó trở thành chậm hơn so với t1 vì nó ghi vào thiết bị xuất chuẩn, sau đó đầu ra sẽ là:

I am thread t1, I'm the runner-up 
I am thread t2, I was first! 

... vì vậy các cuộc gọi đến test_and_set vẫn còn nguyên tử, mặc dù sản lượng không nhất thiết phải theo thứ tự mong đợi.

Bây giờ nếu bạn đã quấn flag trong phương pháp khác (không sắp xếp theo hàng chỉ để đảm bảo), như vậy ...

__declspec(noinline) 
bool wrap() { 
    return !flag.test_and_set(); 
} 

void threadMethod() { 

    bool wasFirst = wrap(); 
    if(wasFirst) cout << "I am thread " << this_thread::get_id() << ", I was first!"  << endl; 
    else   cout << "I am thread " << this_thread::get_id() << ", I'm the runner-up" << endl; 
} 

... sau đó chương trình sẽ không cư xử bất kỳ khác nhau - bởi vì false hoặc true trả lại bool giá trị từ test_and_set() sẽ vẫn nằm trong ngăn xếp của mỗi chuỗi. Ergo, gói atomic_flag không thay đổi nguyên tử của nó.

1

Không, phương pháp isReady() sẽ hoạt động chính xác giống như gọi trực tiếp test_and_set(), đó là nguyên tử.

4

Thuộc tính nguyên tử của nguyên tử C++ đảm bảo rằng một thao tác không thể bị phá vỡ ở giữa. Tức là, đối với một luồng thứ hai quan sát nguyên tử, nó sẽ quan sát trạng thái trước test_and_set hoặc trạng thái sau test_and_set. Đó là không phải có thể cho chủ đề như vậy để lẻn vào một số clear giữa các test và phần set.

Tuy nhiên, điều này chỉ đúng đối với hoạt động của chính nó. Ngay sau khi cuộc gọi test_and_set hoàn tất, tất cả cược sẽ bị tắt. Bạn nên luôn luôn giả định rằng chuỗi thực thi test_and_set có thể bị lấy trước ngay lập tức sau khi hoàn thành hướng dẫn đó, vì vậy bạn không thể giả định rằng bất kỳ lệnh thực thi nào sau test_and_set sẽ vẫn quan sát cùng một trạng thái.

Như vậy, việc thêm lệnh gọi hàm sẽ không khiến bạn gặp rắc rối ở đây.Bất kỳ lệnh nào theo sau nguyên tử phải giả định rằng trạng thái của biến nguyên tử có thể đã thay đổi trong thời gian chờ đợi. Các nguyên tử đưa vào tài khoản bằng cách cung cấp các giao diện được thiết kế theo cách đặc biệt: Ví dụ: test_and_set trả về kết quả của thử nghiệm, vì việc thu thập thông tin đó thông qua một cuộc gọi riêng biệt sẽ không còn nguyên tử nữa.

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