2011-01-21 35 views
22

Tôi có một chương trình C++ trên Linux (CentOS 5.3) sinh sản nhiều chủ đề trong một vòng lặp vô hạn để thực hiện một công việc và ngủ cho một số phút. Bây giờ tôi phải hủy bỏ các chủ đề đang chạy trong trường hợp một thông báo cấu hình mới xuất hiện và bắt đầu một loạt các chủ đề mới, mà tôi đã sử dụng pthread_cancel. Những gì tôi quan sát được, các chủ đề không bị ngừng ngay cả sau khi nhận được chỉ định hủy bỏ, thậm chí một số chủ đề ngủ đã được đưa ra sau khi giấc ngủ đã được hoàn thành.Hủy bỏ một chủ đề bằng cách sử dụng pthread_cancel: tốt thực hành hoặc xấu

Vì hành vi không mong muốn, việc sử dụng lệnh pthread_cancel trong kịch bản đã nêu lên đặt ra câu hỏi về thực hành tốt hay xấu.

Vui lòng nhận xét về cách sử dụng pthread_cancel trong kịch bản được đề cập ở trên.

Trả lời

39

Trong hủy bỏ chuỗi chung không phải là một ý tưởng thực sự tốt. Nó là tốt hơn, bất cứ khi nào có thể, để có một lá cờ được chia sẻ, được sử dụng bởi các chủ đề để thoát ra khỏi vòng lặp. Bằng cách đó, bạn sẽ để cho các chủ đề thực hiện bất kỳ dọn dẹp nào mà họ có thể cần thực hiện trước khi thực sự thoát.

Về vấn đề chuỗi không thực sự hủy, đặc điểm POSIX xác định một tập hợp các điểm hủy (man 7 pthreads). Chỉ có thể hủy các chủ đề tại các điểm đó. Nếu vòng lặp vô hạn của bạn không chứa điểm hủy, bạn có thể thêm một điểm bằng cách gọi pthread_testcancel. Nếu pthread_cancel đã được gọi, sau đó nó sẽ được thực hiện tại thời điểm này.

+5

+1 để tránh hủy, đó là cách nhanh nhất để rò rỉ bộ nhớ và tệ hơn. Hãy hỏi một cách lịch sự thay vào đó :) –

+1

Có vẻ như tôi phải thay đổi logic để chấm dứt chuỗi bằng cách sử dụng cờ được chia sẻ. Nhưng trên lưu ý khác chương trình của tôi đã có chủ đề với nhà nước hủy bỏ thiết lập để ASYNCHRONOUS mà, tôi tin rằng, có liên quan đến chấm dứt ngay lập tức của chủ đề sau khi gọi xử lý dọn dẹp tương ứng. – Mandar

+0

@ user584631: Trang hướng dẫn sử dụng pthreads nói rằng khi chế độ được đặt thành không đồng bộ, việc hủy có thể là ngay lập tức, nhưng hệ thống không bắt buộc phải làm như vậy. –

9

Nếu bạn đang viết mã C++ ngoại lệ an toàn (xem http://www.boost.org/community/exception_safety.html) so với mã của bạn đã sẵn sàng tự nhiên để hủy chuỗi. glibs throws C++ exception on thread cancel, để người hủy của bạn có thể thực hiện công việc dọn dẹp thích hợp.

+3

Nếu OP biết rằng họ sẽ không bao giờ cần phải chạy trên một thực thi pthread khác, đó là OK, nhưng tôi khuyên bạn KHÔNG nên dựa vào việc hủy bỏ thread được thực hiện thông qua các ngoại lệ. Sử dụng cờ sẽ di chuyển luồng thoát ra khỏi lĩnh vực 'nội dung ẩn' và vào mã bạn có thể thấy, giúp các nhà bảo trì sau này dễ dàng hơn.Tôi đã có kinh nghiệm với vấn đề cụ thể này trong nhiều năm và tôi đã kết luận rằng điều tốt nhất là tránh hủy bỏ, bởi vì luôn có SOMETHING mà các chuyến đi bạn lên khi bạn đã hủy bỏ trong hỗn hợp. –

+1

Bài đăng trên blog này mô tả lý do chính xác RAII không thể kết hợp với hủy: https://skaark.wordpress.com/2010/08/26/pthread_cancel-considered-harmful/ – erenon

+1

@erenon Bài viết hay, nhưng nó chỉ là một nửa câu chuyện. Người ta có thể vô hiệu hóa hủy bỏ thread trong destructors. –

0

Tôi muốn sử dụng tăng :: asio.

Cái gì như:

struct Wait { 
    Wait() : timer_(io_service_), run_(true) {} 

    boost::asio::io_service io_service_; 
    mutable boost::asio::deadline_timer timer_; 
    bool run_; 
}; 

void Wait::doWwork() { 
    while (run) { 
    boost::system::error_code ec; 
    timer_.wait(ec); 
    io_service_.run(); 
    if (ec) { 
     if (ec == boost::asio::error::operation_aborted) { 
     // cleanup 
     } else { 
     // Something else, possibly nasty, happened 
     } 
    } 
    } 
} 

void Wait::halt() { 
    run_ = false; 
    timer_.cancel(); 
} 

Một khi bạn đã có đầu tròn nó, ASIO là một công cụ tuyệt vời.

0

Bạn có thể thực hiện tương đương với mã bên dưới.

#include <pthread.h> 
#include <cxxabi.h> 
#include <unistd.h> 
... 
void *Control(void* pparam) 
{ 
    try 
    { 
     // do your work here, maybe long loop 
    } 
    catch (abi::__forced_unwind&) 
    { // handle pthread_cancel stack unwinding exception 
     throw; 
    } 
    catch (exception &ex) 
    { 
     throw ex; 
    } 
} 

int main() 
{ 
    pthread_t tid; 
    int rtn; 
    rtn = pthread_create(&tid, NULL, Control, NULL); 

    usleep(500); 
    // some other work here 

    rtn = pthtead_cancel(tid); 
} 
Các vấn đề liên quan