2012-12-15 28 views

Trả lời

22

Bạn không thể.

std::threads không bị gián đoạn. Bạn có thể sử dụng boost::thread cung cấp tính năng này.

Tăng tính năng này bằng cách xác định "điểm ngắt" mà chuỗi sẽ kết thúc nếu nó bị gián đoạn và đạt đến điểm đó.

Tuy nhiên, phần lớn thời gian suy nghĩ về việc thiết kế lại có thể là cách sạch sẽ và dễ dàng nhất để tiếp cận những gì bạn đang cố gắng đạt được.

Nếu bạn vẫn đang tìm kiếm một C++ 11 thực hiện các chủ đề ngắt thanh toán ra khỏi Anthony Williams (chủ sở hữu của chủ đề tăng) cuốn sách "C++ Concurrency in Action". Anh ta trải qua việc thực hiện cơ bản về cách mà một thứ như vậy có thể đạt được.

std::thread::native_handle cung cấp cho bạn quyền truy cập vào trình xử lý chủ đề cụ thể nền tảng có thể hỗ trợ gián đoạn, tuy nhiên cách tiếp cận này làm cho mã của bạn không thể chuyển và có thể không rõ ràng hơn.

34

câu trả lời của @ bamboon là tốt, tuy nhiên tôi cảm thấy điều này xứng đáng với một tuyên bố mạnh mẽ hơn.

Bất kể ngôn ngữ bạn sử dụng, chương trình của bạn sẽ nhận và giải phóng tài nguyên: bộ nhớ, bộ mô tả tệp ... Đối với các chương trình đơn giản được kích hoạt trong một ảnh, tài nguyên bị rò rỉ không quan trọng nhiều: khi chương trình kết thúc hệ điều hành hiện đại tự động lấy lại các nguồn lực; tuy nhiên đối với các chương trình dài hạn, yêu cầu cơ bản không phải là để rò rỉ tài nguyên, hoặc ít nhất là không lặp lại.

Vì vậy, bạn nên đã được dạy ngay từ đầu rằng khi bạn có được một nguồn tài nguyên bạn sẽ phải đảm bảo nó được phát hành tại một thời điểm:

void foo(int i) { 
    int* array = malloc(sizeof(int) * i); 

    /* do something */ 

    free(array); 
} 

Vì vậy, hãy tự hỏi câu hỏi:

  • điều gì xảy ra khi tôi giết chương trình?
  • điều gì xảy ra khi tôi hủy chuỗi?

Vâng, như chúng tôi đã nói, khi một chương trình kết thúc OS tập hợp các nguồn lực trở lại, vì vậy giả sử (và đây là một số giả định) mà bạn không có được một nguồn tài nguyên trên khác hệ thống HOẶC rằng hệ thống này là tốt được bảo vệ chống lạm dụng như vậy, không có hại, không phạm lỗi.

Tuy nhiên, khi bạn hủy một chuỗi, chương trình vẫn chạy, do đó hệ điều hành không thu thập tài nguyên trở lại. Bộ nhớ bị rò rỉ YOu, bạn đã khóa một tập tin để viết mà bạn không thể mở khóa được nữa, ... Bạn không được hủy các chủ đề.

Ngôn ngữ cấp cao hơn có cách để xử lý điều này: ngoại lệ. Bởi vì các chương trình nên được ngoại lệ an toàn anyway, Java (ví dụ) sẽ giết một sợi bằng cách tạm dừng nó, ném một ngoại lệ tại thời điểm thực hiện, và nhẹ nhàng thư giãn ngăn xếp. Tuy nhiên, chưa có cơ sở nào trong C++.

Có thể không? Không, rõ ràng là không. Trên thực tế, bạn hoàn toàn có thể tái sử dụng các ý tưởng rất giống nhau:

  • Encapsulate std::thread, interruptible_thread lớp cũng sẽ chứa cờ ngắt
  • vượt qua địa chỉ của lá cờ để std::thread khi khởi chạy nó, và lưu nó trong một thread- cách địa phương
  • cụ mã của bạn với check-điểm nơi bạn kiểm tra xem cờ ngắt được thiết lập hay không, và khi nó là ném một ngoại lệ

đó là:

// Synopsis 
class interrupt_thread_exception; 
class interruptible_thread; 
void check_for_interrupt(); 

// Interrupt exception 
class interrupt_thread_exception: public virtual std::exception { 
public: 
    virtual char const* what() const override { return "interrupt"; } 
}; // class interrupt_thread_exception 

// Interruptible thread 
class interruptible_thread { 
public: 
    friend void check_for_interrupt(); 

    template <typename Function, typename... Args> 
    interruptible_thread(Function&& fun, Args&&... args): 
     _thread([](std::atomic_bool& f, Function&& fun, Args&&... args) { 
        _flag_ref = &f; fun(std::forward<Args>(args)...); 
       }, 
       _flag, 
       std::forward<Function>(fun), 
       std::forward<Args>(args)...) 
    {} 

    bool stopping() const { return _flag.load(); } 

    void stop() { _flag.store(true); } 

private: 
    static thread_local std::atomic_bool* _flag_ref = nullptr; 

    std::atomic_bool _flag = false; 
    std::thread _thread; 
}; // class interruptible_thread 

// Interruption checker 
inline void check_for_interrupt() noexcept(false) { 
    if (not interruptible_thread::_flag_ref) { return; } 
    if (not interruptible_thread::_flag_ref->load()) { return; } 

    throw interrupt_thread_exception(); 
} // check_for_interrupt 

Bây giờ bạn chỉ có thể rắc mã luồng của mình bằng séc để ngắt ở những nơi thích hợp.

+5

+1, ** this ** là một khái niệm quan trọng. Các luồng là một tài nguyên và miền bảo mật khác nhau cho các quy trình. Họ đòi hỏi một cách tiếp cận hợp tác hơn là 'đối nghịch'. Cấu trúc lại mã để các luồng có thể chấm dứt một cách duyên dáng khi được yêu cầu. –

+1

'void foo (int)' đã không phải là ngoại lệ an toàn, nếu bạn có một kiểm tra gián đoạn ở giữa '/ * làm điều gì đó */'nó vẫn sẽ là sai. –

+0

Tín hiệu nào? Bạn đang nói về việc ném một ngoại lệ về sự gián đoạn, và một số nền tảng làm tương tự cho pthread_cancel. Nếu một ngoại lệ được ném nó không hoàn thành chức năng. –

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