2010-08-17 20 views
5

Trong C++ đa luồng chương trình rỗng, tôi có tương đương với chạy này trong một thread:trong khi vòng lặp không kiểm tra tình trạng

while(obj->member) { } // waiting for obj->member to be set to false in another thread 

và trong chủ đề khác, obj-> thành viên được thiết lập là false. Ngay cả khi nó được đặt thành false, tuy nhiên, vòng lặp không bị ngắt. Nếu tôi thay đổi nó thành:

while(obj->member) { Sleep(1) } 

Nó hoạt động như mong đợi và ngắt khi obj-> thành viên được đặt thành sai trong chuỗi khác.
Tại sao nó hoạt động như thế này?

+5

Vui lòng không sử dụng chế độ chờ bận - tìm hiểu về biến điều kiện hoặc nguyên thủy đồng bộ hóa tương tự. – Arkadiy

+0

Cái gì? Tôi không có ý tưởng gì đó có nghĩa. – Hock

+0

Tôi sẽ thứ hai những gì @Arkadiy nói (và nếu bạn không có ý tưởng điều đó có nghĩa là gì, bạn cần phải làm rất nhiều đọc trước khi bạn viết bất kỳ mã đa luồng hơn). Ngoài việc chờ đợi bận rộn (mà chỉ là hình thức xấu), mã của bạn cũng không phải là chủ đề an toàn. Với sự đơn giản của những gì bạn đang làm _trong trường hợp chính xác này, tuy nhiên, tôi không nghĩ rằng bạn sẽ gặp phải một vấn đề trên bất kỳ cấu trúc CPU thông thường nào. – rmeador

Trả lời

10

Hãy thử làm thành viên volatile. Điều này sẽ buộc nó phải được lấy từ bộ nhớ mỗi khi nó được sử dụng, thay vì từ một thanh ghi CPU (đó là cách trình biên dịch có thể tối ưu hóa nó.)

6

Obj phải được khai báo volatile. Điều đó nói với trình biên dịch rằng giá trị của nó có thể thay đổi bởi một số luồng khác.

Khi bạn thêm Sleep, trình biên dịch biết các luồng khác đang hoạt động và giả định rằng nó có thể thay đổi.

+0

Trình biên dịch biết rằng từ từ khóa 'volatile', không phải là sự hiện diện của' Sleep'. –

+0

@CareyGregory Ngoại trừ, rõ ràng, trình biên dịch WS có thể biết rằng chỉ từ 'Sleep()', dựa trên OP. –

+0

Có thể, nhưng tôi hoài nghi. Không có lý do tại sao sự hiện diện của 'Ngủ 'chỉ ra có những chủ đề khác trong quá trình này. Thêm 'Sleep' hoặc một số thao tác năng suất khác bên trong một vòng lặp chặt chẽ là rất phổ biến ngay cả trong các ứng dụng đơn luồng. Tôi nghĩ rằng nhiều khả năng vòng lặp unyielding OP chỉ đơn giản là bỏ đói thread khác đủ để nó không bao giờ có thể thiết lập cờ. –

4

Thực tế là nó hoạt động chủ yếu là ngẫu nhiên. Nếu bạn muốn làm những việc như thế này một cách đáng tin cậy, bạn chỉ cần sử dụng một số loại cơ chế IPC do OS cung cấp, có thể với Boost Interprocess (ví dụ: mutex hoặc semaphore) để mang lại một giao diện người dùng di động hơn.

volatile, trong khi thường đưa ra giải pháp cho các vấn đề như thế này, không cần thiết cũng không đủ. Nó có thể làm tổn thương hiệu suất (rất nhiều) nhưng vẫn không đủ để làm cho luồng hoạt động chính xác. Nếu bạn đang lập trình cho .NET, Microsoft đã xác định phiên bản volatile để đảm bảo an toàn chủ đề (ít nhất một mức độ). Nếu không (trong C hoặc C++ thực), đó là ít sử dụng thực sự, và có thể gây ra thiệt hại đáng kể.

Tôi cũng nên đề cập rằng đây là cách dài lần đầu tiên do nhầm lẫn này được thực hiện. Quay trở lại khi nào, không ít quyền lực hơn Andre Alexandrescu đã viết một bài báo khá đáng kể trong Tiến sĩ Dobbs về việc sử dụng volatile cho luồng. Anh ta đã nhận ra rằng anh ta đã sai, nhưng (đến một mức độ lớn) thiệt hại đã được thực hiện - đặc biệt là kể từ khi volatile là oh rất gần để làm những điều đúng mà nó rất dễ nhầm lẫn nó vì phải/hữu ích trong luồng.

0

Có lẽ thư viện luồng của bạn đang tạo bản sao của đối tượng khi tạo chuỗi và thành viên không thực sự được chia sẻ giữa các chuỗi trừ khi nó được khai báo là tĩnh.

+0

Không, đó là một con trỏ đến một đối tượng. – Hock

2

Cách tốt hơn để làm điều này là sử dụng sự kiện thay vì bool. Với một sự kiện, bạn có thể đợi nó mà không cần sử dụng bất kỳ CPU nào, và bạn sẽ không phải ngủ hoặc sử dụng volitile.