2012-08-31 82 views
81

Tôi không cần phải chấm dứt chuỗi chính xác, hoặc làm cho nó đáp ứng với một lệnh "chấm dứt". Tôi quan tâm đến việc chấm dứt thread mạnh mẽ bằng cách sử dụng tinh khiết C++ 11.Làm cách nào để chấm dứt chuỗi trong C++ 11?

+7

Đây là câu hỏi hay về chủ đề này: http://stackoverflow.com/questions/2790346/c0x-thread-interruption "Tất cả các đặc tả ngôn ngữ đều nói rằng hỗ trợ không được xây dựng vào trong sự mệt mỏi tuổi " –

Trả lời

88
  1. Bạn có thể gọi std::terminate() từ bất kỳ chủ đề nào và chuỗi bạn đang đề cập sẽ hết hiệu lực.

  2. Bạn có thể sắp xếp cho ~thread() được thực hiện trên đối tượng của thread mục tiêu, mà không có một can thiệp join() cũng không detach() trên đối tượng đó. Điều này sẽ có tác dụng tương tự như tùy chọn 1.

  3. Bạn có thể thiết kế một ngoại lệ có một destructor mà ném một ngoại lệ. Và sau đó sắp xếp cho các sợi mục tiêu để ném ngoại lệ này khi nó được chấm dứt mạnh mẽ. Phần khó khăn về việc này là nhận được thread mục tiêu để ném ngoại lệ này.

Tùy chọn 1 và 2 không bị rò rỉ nguồn lực nội bộ quá trình, nhưng họ chấm dứt mỗi chủ đề.

Tùy chọn 3 có thể sẽ rò rỉ tài nguyên, nhưng hợp tác một phần trong đó chuỗi đích phải đồng ý ném ngoại lệ.

Không có cách di động nào trong C++ 11 (mà tôi biết) để không hợp tác tiêu diệt một chuỗi đơn trong chương trình đa luồng (nghĩa là không giết tất cả chuỗi). Không có động lực để thiết kế một tính năng như vậy.

Một std::thread có thể có chức năng thành viên này:

native_handle_type native_handle(); 

Bạn có thể có thể sử dụng để gọi một chức năng hệ điều hành phụ thuộc để làm những gì bạn muốn. Ví dụ trên hệ điều hành của Apple, chức năng này tồn tại và native_handle_typepthread_t. Nếu bạn thành công, bạn có khả năng bị rò rỉ tài nguyên.

+56

-1' std :: terminate' giết chết TẤT CẢ các chủ đề, chấm dứt chương trình ... –

+43

@ChrisDodd Số lượt truy cập +1, đó chính xác là những gì anh ta viết trong câu trả lời của mình. – inf

+1

Nitpick nhẹ trên _ "không làm rò rỉ tài nguyên nội bộ" _: Trong khi tất nhiên là hệ điều hành sẽ đòi lại tất cả các tài nguyên sau khi giết quá trình, tài nguyên _are_ bị rò rỉ theo như chương trình được quan tâm. Điều đó thường không liên quan, nhưng vẫn có thể là một vấn đề trong một số trường hợp. 'std :: terminate' không gọi là destructor tĩnh cũng như không xóa các bộ đệm đầu ra, do đó thứ tự các tài nguyên được phát hành không được xác định rõ, cũng không bảo đảm rằng bất kỳ dữ liệu nào của bạn được hiển thị cho người dùng hoặc bằng văn bản để lưu trữ vĩnh viễn hoặc thậm chí nhất quán và đầy đủ. – Damon

25

@Howard Câu trả lời của Hinnant vừa chính xác là toàn diện. Nhưng nó có thể bị hiểu lầm nếu nó được đọc quá nhanh, bởi vì std::terminate() (toàn bộ quá trình) xảy ra có cùng tên với "chấm dứt" mà @AlexanderVX đã ghi nhớ (1 chuỗi).

Tóm tắt: "chấm dứt 1 chuỗi + mạnh (chuỗi đích không hợp tác) + thuần túy C++ 11 = Không có cách nào".

+7

Ahh, # 1 của tôi thực sự rất vui nhộn.Bạn không phải chỉ định chuỗi nào bạn muốn kết thúc mạnh mẽ. Hệ thống chỉ kỳ diệu biết cái nào bạn muốn kết thúc mạnh mẽ và làm nó! –

+3

Vâng, câu trả lời 'std :: terminate()' giống như một câu chuyện Djinn tinh quái cổ điển; nó đáp ứng tất cả mọi thứ trong mong muốn của OP cho lá thư, mặc dù có lẽ không theo cách anh * có nghĩa là *. Hài hước understated làm tôi mỉm cười. :-) –

+0

Chỉ cần có để ngăn chặn người mới C++ vô tội từ việc hy vọng của họ lên quá xa/quá lâu. –

4

Câu hỏi này thực sự có tính chất sâu sắc hơn và hiểu biết tốt về khái niệm đa luồng nói chung sẽ cung cấp cho bạn thông tin chi tiết về chủ đề này. Trong thực tế, không có bất kỳ ngôn ngữ hoặc hệ điều hành nào cung cấp cho bạn cơ sở cho việc chấm dứt chuỗi không đồng bộ đột ngột mà không cảnh báo để không sử dụng chúng. Và tất cả các môi trường thực thi này đều khuyến khích nhà phát triển hoặc thậm chí yêu cầu xây dựng các ứng dụng đa luồng trên cơ sở chấm dứt luồng hợp tác hoặc đồng bộ. Lý do cho các quyết định và lời khuyên chung này là tất cả chúng được xây dựng trên nền tảng của cùng một mô hình đa luồng chung.

Hãy so sánh các khái niệm đa xử lý và đa luồng để hiểu rõ hơn các ưu điểm và giới hạn của khái niệm thứ hai.

Nhân xử lý giả định chia tách toàn bộ môi trường thực thi thành tập hợp các quy trình được cô lập hoàn toàn do hệ điều hành kiểm soát.Quá trình kết hợp và cô lập trạng thái môi trường thực thi bao gồm bộ nhớ cục bộ của quá trình và dữ liệu bên trong nó và tất cả các tài nguyên hệ thống như tệp, ổ cắm, đối tượng đồng bộ hóa. Cách ly là một đặc tính quan trọng của quá trình, bởi vì nó giới hạn sự lan truyền lỗi bởi các đường biên của quá trình. Nói cách khác, không một quy trình nào có thể ảnh hưởng đến tính nhất quán của bất kỳ quá trình nào khác trong hệ thống. Điều này cũng đúng đối với hành vi của quy trình nhưng theo cách ít bị giới hạn và mờ hơn. Trong môi trường như vậy, bất kỳ quá trình nào có thể bị giết trong bất kỳ khoảnh khắc "tùy ý" nào, bởi vì trước hết mỗi quá trình được phân lập, thứ hai, hệ điều hành có kiến ​​thức đầy đủ về tất cả các tài nguyên được sử dụng bởi quy trình và có thể giải phóng tất cả chúng mà không bị rò rỉ. bởi hệ điều hành không thực sự trong thời điểm tùy ý, nhưng về số lượng các điểm được xác định rõ, nơi trạng thái của quá trình được biết đến.

Ngược lại, xử lý đa luồng giả định chạy nhiều luồng trong cùng một quy trình. Nhưng tất cả các chủ đề này được chia sẻ cùng một hộp cách ly và không có bất kỳ điều khiển hệ điều hành nào của trạng thái bên trong của quá trình. Kết quả là bất kỳ luồng nào cũng có thể thay đổi trạng thái quá trình toàn cầu cũng như làm hỏng nó. Đồng thời, các điểm trong đó trạng thái của luồng được biết là an toàn để tiêu diệt một luồng hoàn toàn phụ thuộc vào logic ứng dụng và không được biết cho cả hệ điều hành lẫn thời gian chạy ngôn ngữ lập trình. Kết quả là chấm dứt chuỗi tại thời điểm tùy ý có nghĩa là giết nó tại điểm bất kỳ của đường dẫn thực thi và có thể dễ dàng dẫn đến hỏng dữ liệu toàn bộ quá trình, bộ nhớ và xử lý rò rỉ, rò rỉ chủ đề và spinlocks và các nguyên tố đồng bộ hóa trong quá trình bên trong khác trạng thái đóng ngăn các luồng khác trong tiến trình. Do đó, cách tiếp cận chung là buộc các nhà phát triển triển khai chấm dứt chuỗi đồng bộ hoặc hợp tác, trong đó một luồng có thể yêu cầu chấm dứt luồng khác và luồng khác trong điểm được xác định rõ có thể kiểm tra yêu cầu này và bắt đầu quy trình tắt từ trạng thái được xác định rõ ràng với việc phát hành tất cả các tài nguyên toàn hệ thống toàn cầu và các tài nguyên toàn bộ quy trình địa phương theo cách an toàn và nhất quán.

+2

Đây không phải là câu trả lời hữu ích. Đa xử lý không có liên quan ở đây và các quan sát về đa luồng khá rộng. – MSalters

+0

Những gì tôi muốn nói và nói chi tiết là mô hình đa luồng không cung cấp cách thức chính xác của việc chấm dứt chuỗi mạnh mẽ. C++ muốn làm theo các mô hình rõ ràng bao gồm cả mô hình bộ nhớ, mô hình đa luồng vv Phương pháp kết thúc chủ đề mạnh mẽ vốn đã không an toàn. Nếu ủy ban tiêu chuẩn C++ sẽ buộc phải thêm nó vào C++, nó sẽ được thực hiện với câu lệnh tiếp theo "Phương thức chấm dứt() chấm dứt thực thi luồng. Hành vi không xác định.", Sẽ giống như "làm cho một số phép thuật và (có thể) chấm dứt chuỗi ". – ZarathustrA

2

Mẹo sử dụng chức năng hệ điều hành phụ thuộc vào phương chấm dứt hoặc C++ Chủ đề:

  1. std::thread::native_handle() chỉ có thể nhận của chủ đề hợp lệ có nguồn gốc xử lý loại trước khi gọi join() hoặc detach(). Sau đó, native_handle() trả lại 0 - pthread_cancel() sẽ coredump.

  2. Để gọi một cách hiệu quả chức năng chấm dứt chủ đề nguồn gốc (ví dụ pthread_cancel), bạn cần phải lưu tay cầm có nguồn gốc trước khi gọi std::thread::join() hoặc std::thread::detach(). Vì vậy mà terminator mẹ đẻ của bạn luôn luôn có một tay cầm có nguồn gốc hợp lệ để sử dụng.

Giải thích thêm vui lòng tham khảo: http://bo-yang.github.io/2017/11/19/cpp-kill-detached-thread

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