2011-09-11 31 views
39

Tôi nhận được một ++ lỗi C với luồng:C++ chấm dứt gọi mà không có một ngoại lệ hoạt động

terminate called without an active exception 
Aborted 

Đây là mã:

#include <queue> 
#include <thread> 
#include <mutex> 
#include <condition_variable> 

template<typename TYPE> 
class blocking_stream 
{ 
public: 
    blocking_stream(size_t max_buffer_size_) 
     : max_buffer_size(max_buffer_size_) 
    { 
    } 

    //PUSH data into the buffer 
    blocking_stream &operator<<(TYPE &other) 
    { 
     std::unique_lock<std::mutex> mtx_lock(mtx); 
     while(buffer.size()>=max_buffer_size) 
      stop_if_full.wait(mtx_lock); 

     buffer.push(std::move(other)); 

     mtx_lock.unlock(); 
     stop_if_empty.notify_one(); 
     return *this; 
    } 
    //POP data out of the buffer 
    blocking_stream &operator>>(TYPE &other) 
    { 
     std::unique_lock<std::mutex> mtx_lock(mtx); 
     while(buffer.empty()) 
      stop_if_empty.wait(mtx_lock); 

     other.swap(buffer.front()); 
     buffer.pop(); 

     mtx_lock.unlock(); 
     stop_if_full.notify_one(); 
     return *this; 
    } 

private: 
    size_t max_buffer_size; 
    std::queue<TYPE> buffer; 
    std::mutex mtx; 
    std::condition_variable stop_if_empty, 
          stop_if_full; 
    bool eof; 
}; 

tôi làm mẫu mã của tôi xung quanh ví dụ này: http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

Tôi đang làm gì sai và cách khắc phục lỗi?

+3

Bạn có 'tham gia' tất cả các chủ đề của bạn trong chương trình chính không? –

+0

Hiển thị cho chúng tôi phần còn lại của mã. – Matt

+1

@Kerrek ah ha điều này đã khắc phục được sự cố, tôi không biết tại sao dù tôi chắc chắn rằng chủ đề chính vẫn chưa chấm dứt trước khi công nhân kết thúc. Cũng làm alogorithms khóa của tôi nhìn phải không? – 111111

Trả lời

63

Khi đối tượng chuỗi nằm ngoài phạm vi và ở trạng thái có thể kết nối, chương trình sẽ bị chấm dứt. Ủy ban Tiêu chuẩn có hai tùy chọn khác cho destructor của một thread joinable. Nó có thể lặng lẽ tham gia - nhưng tham gia có thể không bao giờ trở lại nếu sợi bị mắc kẹt. Hoặc nó có thể tách thread (một thread tách rời không thể join được). Tuy nhiên, các chủ đề tách rời là rất phức tạp, vì chúng có thể tồn tại cho đến khi kết thúc chương trình và làm rối tung việc giải phóng tài nguyên. Vì vậy, nếu bạn không muốn chấm dứt chương trình của mình, hãy đảm bảo bạn tham gia (hoặc tách) mọi chuỗi.

+0

"Khi đối tượng chuỗi nằm ngoài phạm vi và nó ở trạng thái có thể kết nối, chương trình sẽ bị chấm dứt" Bạn có thể cung cấp một ví dụ đơn giản, có thể tái sản xuất được không? Ví dụ trong OP là một chút phức tạp. –

+1

Và tuyên bố đó có vẻ mâu thuẫn với câu trả lời này: http://stackoverflow.com/a/3970921/148668 –

+4

@mangledorf: Lưu ý rằng họ đang nói aobut boost :: thread và tôi đang nói về std :: thread. Cả hai có hành vi hủy diệt khác nhau. Đây là một quyết định có ý thức về một phần của Ủy ban. –

22

Làm thế nào để tái tạo lỗi rằng:

#include <iostream> 
#include <stdlib.h> 
#include <string> 
#include <thread> 
using namespace std; 
void task1(std::string msg){ 
    cout << "task1 says: " << msg; 
} 
int main() { 
    std::thread t1(task1, "hello"); 
    return 0; 
} 

Biên dịch và chạy:

[email protected] ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11 
[email protected] ~/foo4/39_threading $ ./s 
terminate called without an active exception 
Aborted (core dumped) 

Bạn nhận được lỗi rằng vì bạn đã không tham gia hoặc tách thread của bạn.

Một cách để sửa chữa nó, tham gia các chủ đề như thế này:

#include <iostream> 
#include <stdlib.h> 
#include <string> 
#include <thread> 
using namespace std; 
void task1(std::string msg){ 
    cout << "task1 says: " << msg; 
} 
int main() { 
    std::thread t1(task1, "hello"); 
    t1.join(); 
    return 0; 
} 

Sau đó biên dịch và chạy:

[email protected] ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11 
[email protected] ~/foo4/39_threading $ ./s 
task1 says: hello 

Một cách khác để sửa chữa nó, tách nó như thế này:

#include <iostream> 
#include <stdlib.h> 
#include <string> 
#include <unistd.h> 
#include <thread> 
using namespace std; 
void task1(std::string msg){ 
    cout << "task1 says: " << msg; 
} 
int main() 
{ 
    { 

     std::thread t1(task1, "hello"); 
     t1.detach(); 

    } //thread handle is destroyed here, as goes out of scope! 

    usleep(1000000); //wait so that hello can be printed. 
} 

Biên dịch và chạy:

[email protected] ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11 
[email protected] ~/foo4/39_threading $ ./s 
task1 says: hello 

Đọc trên tách các chuỗi C++ và tham gia chuỗi C++.

+0

trong ngữ cảnh này, việc sử dụng usleep() có ý nghĩa chỉ khi luồng được tách ra và tay cầm đã bị hủy (bằng cách thoát khỏi phạm vi). SO tôi đã chỉnh sửa mã của bạn để phản ánh điều này. – Nawaz

4

Eric Leschinski và Bartosz Milewski đã đưa ra câu trả lời. Ở đây, tôi sẽ cố gắng trình bày nó một cách thân thiện với người mới bắt đầu hơn.

Khi một sợi đã được bắt đầu trong vòng một phạm vi (mà bản thân đang chạy trên một sợi), người ta phải đảm bảo rõ ràng là một trong những điều sau đây sẽ xảy ra trước khi thread đi ra khỏi phạm vi:

  • Thời gian chạy thoát ra khỏi phạm vi, chỉ sau khi luồng đó kết thúc thực hiện. Điều này đạt được bằng cách tham gia với chủ đề đó. Lưu ý ngôn ngữ, đó là phạm vi bên ngoài tham gia với chuỗi đó.
  • Thời gian chạy để lại chuỗi chạy tự chạy. Vì vậy, chương trình sẽ thoát khỏi phạm vi, cho dù luồng này đã hoàn thành thực thi hay chưa. Chuỗi này thực thi và thoát khỏi chính nó. Điều này đạt được bằng cách tách sợi chỉ. Điều này có thể dẫn đến các vấn đề, ví dụ, nếu thread đề cập đến các biến trong phạm vi bên ngoài đó.

Lưu ý, vào thời điểm chuỗi được nối hoặc tách ra, nó có thể được thực hiện tốt. Tuy nhiên, một trong hai thao tác phải được thực hiện một cách rõ ràng.

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