アクティブな例外なしで呼び出されたC ++終了


94

スレッドでC ++エラーが発生します:

terminate called without an active exception
Aborted

コードは次のとおりです。

#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;   
};

この例を中心にコードをモデル化しました:http//www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

何が間違っているのですか?エラーを修正するにはどうすればよいですか?


9
あなたは、joinあなたのメインプログラムでは、すべてのスレッドをINGの?
Kerrek SB 2011

残りのコードを見せてください。
マット

2
@Kerrekああ、これで問題が解決しました。ワーカーが終了する前にメインスレッドが終了しなかったのは確かですが、理由はわかりません。また、私のロックのアルゴリズムは正しく見えますか?
111111 2011

問題を再現するコンパイル可能なコードをお願いします。
マーティンヨーク

3
この場合、ランタイムはより良い診断を発行できるようですか?
ネモ

回答:


127

スレッドオブジェクトがスコープ外になり、結合可能な状態になると、プログラムは終了します。標準委員会には、結合可能なスレッドのデストラクタに対して他に2つのオプションがありました。静かに結合できますが、スレッドがスタックしていると結合が戻らない場合があります。または、スレッドを切り離すことができます(切り離されたスレッドは結合できません)。ただし、デタッチされたスレッドは、プログラムが終了するまで存続し、リソースの解放を台無しにする可能性があるため、非常に注意が必要です。したがって、プログラムを終了したくない場合は、必ずすべてのスレッドに参加(またはデタッチ)してください。


1
「スレッドオブジェクトがスコープ外に出て、結合可能な状態になると、プログラムは終了します」これの非常に単純で再現可能な例を提供できますか?OPの例は少し複雑です。
アレックジェイコブソン2012

1
そして、その声明はこの答えと矛盾しているようです:stackoverflow.com/a/3970921/148668
Alec Jacobson

5
@mangledorf:彼らがブースト::スレッドについて話していることに注意してください。私はstd :: threadについて話しているのです。これら2つの破壊動作は異なります。これは委員会側の意識的な決定でした。
Bartosz Milewski 2012

でこの問題が発生した場合はどうなりますstd::asyncか?そこで作成される可能性のあるスレッドをどのように結合/切り離しますか?結果として生じるfutureを待つだけでは十分ではないようです。これは、スレッドが「スレッドプールからのものである可能性がある」ことを示しており、futureのwait()は、プール内のスレッドを終了することを実際には意味しません(とにかく正気のスレッドプールには意味がありません)。
ジェイソンC

2
C ++ 20で、デストラクタstd::jthreadを呼び出す更新だけです.join()(スコープ外になるため)。RAIIによく従うので、個人的にはどちらが好きですか。
pooya 1319

46

そのエラーを再現する方法:

#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;
}

コンパイルして実行します。

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

スレッドに参加またはデタッチしなかったため、このエラーが発生します。

これを修正する1つの方法は、次のようにスレッドに参加することです。

#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;
}

次に、コンパイルして実行します。

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello

それを修正する別の方法は、次のように切り離します。

#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.
}

コンパイルして実行します。

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello

C ++スレッドのデタッチとC ++スレッドの結合について読んでください。


1
このコンテキストでは、usleep()の使用は、スレッドが切り離され、ハンドルが(スコープ外になることによって)破棄された場合にのみ意味があります。だから私はこれを反映するようにあなたのコードを編集しました。
nawaz 2015

17

EricLeschinskiとBartoszMilewskiはすでに答えを出しました。ここでは、より初心者に優しい方法でそれを提示しようとします。

スレッドがスコープ内で開始されたら(それ自体がスレッド上で実行されている)、スレッドがスコープ外になる前に、次のいずれかが発生することを明示的に確認する必要があります。

  • ランタイムは、そのスレッドの実行が終了した後にのみスコープを終了します。これは、そのスレッドと結合することによって実現されます。言語に注意してください。そのスレッドと結合するのは外部スコープです。
  • ランタイムはスレッドをそのままにして、それ自体で実行します。したがって、このスレッドの実行が終了したかどうかに関係なく、プログラムはスコープを終了します。このスレッドは実行され、自動的に終了します。これは、スレッドを切り離すことによって実現されます。これにより、たとえば、スレッドがその外部スコープの変数を参照している場合に問題が発生する可能性があります。

スレッドが結合または切り離されるまでに、スレッドの実行が正常に終了している可能性があることに注意してください。それでも、2つの操作のいずれかを明示的に実行する必要があります。


1

プログラムが停止している限り、スレッドのデタッチまたは結合がないと、このエラーが発生します。スレッドを切り離して結合せずに、スレッドを作成した後に無限ループを与える必要があります。

int main(){

std::thread t(thread,1);

while(1){}

//t.detach();
return 0;}

スリープまたはループした後、スレッドを切り離したり結合したりできることも興味深いです。また、この方法では、このエラーは発生しません。

以下の例は、3番目のスレッドがメインダイの前にジョブを実行できないことも示しています。ただし、コードのどこかでデタッチする限り、このエラーも発生しません。3番目のスレッドは8秒間スリープしますが、メインは5秒で終了します。

void thread(int n) {std::this_thread::sleep_for (std::chrono::seconds(n));}

int main() {
std::cout << "Start main\n";
std::thread t(thread,1);
std::thread t2(thread,3);
std::thread t3(thread,8);
sleep(5);

t.detach();
t2.detach();
t3.detach();
return 0;}

1

年、スレッドはjoin()でなければなりません。メイン出口のとき


1
この回答は、おそらく別の回答に添付されたコメントに適しています。そして、私は言わなければなりません、Stack Overflowへようこそ!
コンタンゴ

0

まず、スレッドを定義します。また、スレッドデストラクタを呼び出す前にjoin()またはdetach()を呼び出さなかった場合、プログラムは中止されます。

次のように、最初にjoinを呼び出さずに(終了するのを待つために)スレッドデストラクタを呼び出すか、デストラクタを呼び出すと、すぐにstd :: terminateを呼び出してプログラムを終了することが保証されます。

デストラクタでjoinable()スレッドを暗黙的にデタッチまたは結合すると、例外が発生した場合にのみ発生する正確性(デタッチの場合)またはパフォーマンス(結合の場合)のバグのデバッグが困難になる可能性があります。したがって、プログラマーは、スレッドがまだ参加可能である間は、デストラクタが実行されないようにする必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.