2014-12-10 15 views
18

Đưa ra dưới đây:C++ 11: Điều gì sẽ xảy ra nếu bạn không gọi tham gia() cho std :: chủ đề

void test() 
{ 
    std::chrono::seconds dura(20); 
    std::this_thread::sleep_for(dura); 
} 

int main() 
{ 
    std::thread th1(test); 
    std::chrono::seconds dura(5); 
    std::this_thread::sleep_for(dura); 
    return 0; 
} 

main sẽ thoát sau 5 giây, điều gì sẽ xảy ra với th1 mà vẫn thực hiện?

Sản phẩm có tiếp tục thực hiện cho đến khi hoàn thành ngay cả khi đối tượng chủ đề th1 bạn đã xác định trong main vượt quá phạm vi và bị hủy không?

th1 chỉ đơn giản là ngồi ở đó sau khi hoàn thành việc thực hiện hoặc bằng cách nào đó được dọn sạch khi chương trình chấm dứt?

Điều gì sẽ xảy ra nếu chuỗi được tạo trong một hàm, không phải main - luồng có nằm lại cho đến khi chương trình chấm dứt hoặc khi chức năng không nằm trong phạm vi?

Có an toàn để chỉ đơn giản là không gọi join cho một chủ đề nếu bạn muốn một số loại hành vi thời gian chờ trên thread?

+0

Tại sao bạn không thử? – Drop

+14

@Drop Bởi vì đó không phải là cách đáng tin cậy để học về * đảm bảo *. – dyp

+0

@dyp không yêu cầu trên Stackoverflow. Bằng cách biên dịch và chạy dòng chảy 5 dòng này, ít nhất anh ta có thể tìm ra manh mối. Chỉ có một nguồn đảm bảo - một tiêu chuẩn. – Drop

Trả lời

16

Nếu bạn chưa tách hoặc tham gia một thread khi destructor được gọi nó sẽ gọi std::terminate, chúng ta có thể thấy điều này bằng cách vào draft C++11 standard chúng ta thấy rằng phần 30.3.1.3chủ đề destructor nói:

Nếu joinable(), gọi std :: terminate(). Nếu không, không có tác dụng. [ Lưu ý: Hoặc tách hoàn toàn hoặc tham gia một chuỗi có thể join() trong phá hủy của nó có thể gây khó khăn cho việc sửa lỗi (đối với các lỗi tách) hoặc hiệu năng (để tham gia) chỉ xảy ra khi ngoại lệ được nâng lên. Do đó, lập trình viên phải đảm bảo rằng trình phá hủy không bao giờ được thực hiện trong khi luồng vẫn có thể nối được. -end note]

như đối với một lý do cho hành vi này chúng ta có thể tìm thấy một bản tóm tắt tốt trong (Not) using std::thread

Tại sao destructor của a thread joinable đã gọi std :: chấm dứt?Sau khi tất cả, destructor có thể tham gia với các chủ đề con , hoặc nó có thể tách ra từ các chủ đề con, hoặc nó có thể hủy bỏ chủ đề. Trong ngắn hạn, bạn không thể tham gia vào destructor vì điều này sẽ kết quả trong bất ngờ (không được chỉ định rõ ràng trong mã) chương trình đóng băng trong trường hợp f2 ném.

và một ví dụ sau và cũng có thể nói:

Bạn không thể tách vì nó sẽ có nguy cơ tình hình nơi chủ đề chính rời khỏi phạm vi mà các sợi con đã được đưa ra vào, và các chủ đề con giữ chạy và giữ tham chiếu đến phạm vi đã bị biến mất.

Bài báo tham chiếu N2802: A plea to reconsider detach-on-destruction for thread objects đó là lập luận chống lại đề nghị trước đó đã tách trên phá hủy nếu joinable và nó nhấn mạnh rằng một trong hai lựa chọn thay thế sẽ được tham gia mà có thể dẫn đến sự bế tắc thay thế khác là những gì chúng ta có ngày hôm nay là std::terminate nếu hủy.

5

std::thread::~thread()

Nếu * này đã một chủ đề liên quan (joinable() == true), std::terminate() được gọi

Nguồn: http://en.cppreference.com/w/cpp/thread/thread/~thread

Điều này có nghĩa rằng chương trình như thế này không phải là ở tất cả nổi hình thành hoặc an toàn.

Lưu ý rằng tuy nhiên, boost::thread::~thread() gọi detach() thay vào đó trong trường hợp này. (như sử dụng dyp được nêu trong ý kiến, hành vi này bị phản đối trong các phiên bản gần đây)

Bạn luôn có thể workaround này sử dụng RAII. Chỉ cần quấn sợi của bạn bên trong một lớp khác, điều đó sẽ có hành vi mong muốn về sự hủy diệt.

+2

Hành vi tăng cường đó không được chấp nhận: http://www.boost.org/doc/libs/1_57_0/doc/html/thread/thread_management.html#thread.thread_management.thread.destructor – dyp

+0

@dyp Cool! Tôi có thể thêm nó vào câu trả lời của tôi không? ;) – Drop

+1

Vâng, tất nhiên. Đó là lý do tại sao tôi đang bình luận :) – dyp

1

Trong C++ 11, bạn phải chỉ định rõ ràng 'điều gì xảy ra' khi chuỗi mới được tạo ra nằm ngoài phạm vi (chúng tôi gọi nó là dtor). Đôi khi, khi chúng tôi chắc chắn rằng các chủ đề chính, đang tiếp tục, và chủ đề của chúng tôi đang hoạt động như 'đường ống', nó là an toàn để 'tách()' chúng; và đôi khi khi chúng tôi chờ các chủ đề WORKER của chúng tôi hoàn thành các hoạt động của họ, chúng tôi sẽ tham gia() chúng.

Khi this nói, lập trình viên phải đảm bảo rằng trình hủy không bao giờ được thực hiện trong khi chuỗi vẫn có thể nối được.

Chỉ định chiến lược đa luồng của bạn. Trong ví dụ này, std::terminate() được gọi.

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