2010-02-07 43 views
6

Hãy tưởng tượng một chương trình có hai luồng. Họ đang chạy đoạn mã sau (CAS đề cập đến Compare and Swap):Có thể cạnh tranh các hoạt động nguyên tử không?

// Visible to both threads 
static int test; 

// Run by thread A 
void foo() 
{ 
    // Check if value is 'test' and swap in 0xdeadbeef 
    while(!CAS(&test, test, 0xdeadbeef)) {} 
} 

// Run by thread B 
void bar() 
{ 
    while(1) { 
     // Perpetually atomically write rand() into the test variable 
     atomic_write(&test, rand()); 
    } 
} 

Có thể cho thread B để vĩnh viễn gây ra thread của CAS thất bại như vậy 0xdeadbeef không bao giờ được ghi vào 'thử'? Hay tự nhiên lập kế hoạch jitter có nghĩa là trong thực tế điều này không bao giờ xảy ra? Điều gì sẽ xảy ra nếu một số công việc được thực hiện bên trong vòng lặp while A?

Trả lời

6

Là một vấn đề lý thuyết, có. Nếu bạn có thể quản lý bằng cách nào đó để có được hai chuỗi đang chạy ở chế độ khóa như thế này

 
    time  thread A  thread B 
    ----  --------  -------- 
    ||  CAS 
    ||     atomic_write 
    ||  CAS 
    \/     atomic_write 

Sau đó, CAS sẽ không bao giờ trở lại đúng sự thật.

Trong thực tế, điều này sẽ không bao giờ xảy ra khi các chủ đề chia sẻ CPU/Core và không xảy ra khi các luồng đang chạy trên các CPU hoặc lõi khác nhau. Trong thực tế nó là cực kỳ không xảy ra trong nhiều chu kỳ, và thiên văn không xảy ra với nhiều hơn một lượng tử lịch trình.

Và đó là nếu mã này

void foo() 
{ 
    // Check if value is 'test' and swap in 0xdeadbeef 
    while(!CAS(&test, test, 0xdeadbeef)) {} 
} 

làm những gì nó xuất hiện để làm, mà là để lấy giá trị hiện tại của test, và so sánh nó với test để xem nếu nó đã thay đổi. Trong các lần lặp lại của thế giới thực của CAS sẽ được phân tách bằng mã thực hiện công việc thực tế. Các từ khóa volatile sẽ là cần thiết để đảm bảo rằng trình biên dịch lấy thử nghiệm trước khi gọi CAS thay vì giả định rằng một bản sao nó vẫn có thể có trong sổ đăng ký vẫn hợp lệ.

Hoặc giá trị bạn sẽ thử nghiệm sẽ không là giá trị hiện tại của thử nghiệm, mà là một số loại giá trị được biết gần đây nhất.

Nói cách khác, ví dụ mã này là một thử nghiệm của lý thuyết, nhưng bạn sẽ không sử dụng CAS như thế này trong thực tế, vì vậy ngay cả khi bạn có thể làm được điều này, nó không nhất thiết phải cho bạn biết thất bại khi được sử dụng trong các thuật toán thế giới thực.

+0

Tại sao nó chỉ thực hiện hai lần? Nếu nó tối ưu hóa việc lấy thử nghiệm, không phải là hiệu ứng mà nó có thể lặp * mãi mãi *? Việc so sánh và hoán đổi sẽ luôn thất bại bởi vì so sánh sẽ vĩnh viễn sai, trừ khi bạn may mắn và rand() trả về giá trị mà kiểm tra xảy ra trước khi luồng A vào vòng lặp và luồng A xảy ra để chạy vào đúng thời điểm. –

+0

Ngoài ra khi bạn nói không chắc chắn, bạn có nghĩa là không đủ rằng bạn sẽ không phản đối việc sử dụng mã này trong phần mềm sản xuất? Sẽ rất thú vị khi thử tính toán xác suất được đơn giản hóa. –

+0

Khi cá nhân tôi nói không chắc chắn khi đề cập đến một vấn đề luồng, tôi có nghĩa là tôi muốn nó cố định để nó thực sự không xảy ra. Tôi đã có quá nhiều "sẽ không xảy ra" nổ tung lên tôi. –

2

Đói đói chắc chắn có thể xảy ra trong những trường hợp như vậy. Trích dẫn the wikipedia page,

Nó cũng đã chỉ ra rằng rộng rãi có sẵn nguyên tử có điều kiện nguyên thủy, CAS và LL/SC, không có thể cung cấp đói miễn triển khai của nhiều dữ liệu chung cấu trúc mà không cần chi phí bộ nhớ phát triển tuyến tính trong số các chủ đề . Do đó, các thuật toán miễn phí là hiếm, cả trong nghiên cứu và trong thực tế.

(Xem liên kết từ trang được đề cập để tìm bằng chứng toán học).

+0

Tùy thuộc vào cách sử dụng CAS, thường có thể đảm bảo rằng sẽ không có tác vụ nào bị chặn trừ khi một số tác vụ khác thực hiện tiến trình chuyển tiếp. Nếu tập hợp công việc được thực hiện là hữu hạn, việc đảm bảo đó sẽ lần lượt có nghĩa là mọi công việc cuối cùng sẽ hoàn thành. Thời gian tối đa cho bất kỳ nhiệm vụ cụ thể nào để hoàn thành có thể được tính như một hàm của tổng số lượng công việc sẽ đến.Trong một hệ thống không có đói, thời gian cho một nhiệm vụ hoàn thành khi nó bắt đầu sẽ bị chặn ngay cả khi tải công việc không, nhưng có thời gian bị ràng buộc liên quan đến khối lượng công việc vẫn hữu ích. – supercat

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