C ++ terminate dipanggil tanpa pengecualian aktif

94

Saya mendapatkan kesalahan C ++ dengan threading:

terminate called without an active exception
Aborted

Ini kodenya:

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

Saya membuat model kode saya di sekitar contoh ini: http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

Apa yang saya lakukan salah dan bagaimana cara memperbaiki kesalahan tersebut?

111111
sumber
9
Apakah Anda joinmemasukkan semua utas Anda dalam program utama Anda?
Kerrek SB
Tunjukkan kode lainnya kepada kami.
Matt
2
@Kerrek ah ha ini memperbaiki masalah, saya tidak tahu mengapa meskipun saya yakin utas utama tidak berhenti sebelum para pekerja selesai. Juga apakah alogoritma penguncian saya terlihat benar?
111111
Harap kompilasi kode yang mereproduksi masalah.
Martin York
3
Sepertinya runtime bisa mengeluarkan diagnostik yang lebih baik dalam kasus ini?
Nemo

Jawaban:

127

Saat objek utas keluar dari ruang lingkup dan berada dalam status dapat digabungkan, program dihentikan. Komite Standar memiliki dua opsi lain untuk penghancur utas yang dapat disambung. Itu bisa bergabung secara diam-diam - tetapi bergabung mungkin tidak akan pernah kembali jika utas macet. Atau bisa juga melepaskan utas (utas yang terlepas tidak dapat digabungkan). Namun, utas yang terlepas sangat rumit, karena mereka mungkin bertahan hingga akhir program dan mengacaukan pelepasan sumber daya. Jadi jika Anda tidak ingin menghentikan program Anda, pastikan Anda bergabung (atau melepaskan) setiap utas.

Bartosz Milewski
sumber
1
"Saat objek utas keluar dari ruang lingkup dan dalam status dapat digabungkan, program dihentikan" Bisakah Anda memberikan contoh sederhana yang dapat direproduksi? Contoh di OP agak rumit.
Alec Jacobson
1
Dan pernyataan itu tampaknya bertentangan dengan jawaban ini: stackoverflow.com/a/3970921/148668
Alec Jacobson
5
@mangledorf: Perhatikan bahwa mereka berbicara aobut boost :: thread dan saya berbicara tentang std :: thread. Keduanya memiliki perilaku penghancuran yang berbeda. Ini adalah keputusan sadar dari pihak Komite.
Bartosz Milewski
Bagaimana jika Anda mengalami masalah ini std::async? Bagaimana Anda menggabungkan / melepaskan utas apa pun yang mungkin dibuat di sana? Tampaknya menunggu di masa depan yang dihasilkan tidak akan cukup, karena ini mengatakan bahwa utas bisa "berpotensi dari kumpulan utas", dan penantian masa depan () tidak benar-benar menyiratkan penghentian utas di kumpulan (dan itu tidak akan lagian tidak masuk akal untuk kumpulan benang yang waras).
Jason C
2
Hanya pembaruan yang di C ++ 20, std::jthreadakan memanggil .join()destruktor (karena keluar dari ruang lingkup). Yang secara pribadi saya lebih suka karena mengikuti RAII dengan lebih baik.
pooya13
46

Bagaimana cara mereproduksi kesalahan itu:

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

Kompilasi dan jalankan:

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)

Anda mendapatkan kesalahan itu karena Anda tidak bergabung atau melepaskan utas Anda.

Salah satu cara untuk memperbaikinya, gabung dengan utas seperti ini:

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

Kemudian kompilasi dan jalankan:

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

Cara lain untuk memperbaikinya, lepaskan seperti ini:

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

Kompilasi dan jalankan:

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

Baca tentang melepaskan utas C ++ dan bergabung dengan utas C ++.

Eric Leschinski
sumber
1
dalam konteks ini, penggunaan usleep () masuk akal hanya jika utas dilepaskan dan pegangan telah dihancurkan (dengan keluar dari ruang lingkup). JADI saya mengedit kode Anda untuk mencerminkan ini.
Nawaz
17

Eric Leschinski dan Bartosz Milewski telah memberikan jawabannya. Di sini, saya akan mencoba menyajikannya dengan cara yang lebih ramah pemula.

Setelah utas dimulai dalam suatu lingkup (yang berjalan sendiri pada utas), seseorang harus secara eksplisit memastikan salah satu hal berikut terjadi sebelum utas keluar dari cakupan:

  • Waktu proses keluar dari cakupan, hanya setelah thread tersebut selesai dieksekusi. Ini dicapai dengan bergabung dengan utas itu. Perhatikan bahasanya, itu adalah ruang lingkup luar yang bergabung dengan utas itu.
  • Waktu proses membiarkan utas berjalan sendiri. Jadi, program akan keluar dari ruang lingkup, apakah thread ini selesai dijalankan atau tidak. Utas ini dijalankan dan keluar dengan sendirinya. Ini dicapai dengan melepaskan utas. Hal ini dapat menyebabkan masalah, misalnya, jika utas merujuk ke variabel dalam cakupan luar tersebut.

Perhatikan, pada saat utas digabungkan atau dilepaskan, utas mungkin telah selesai dijalankan. Masih salah satu dari dua operasi tersebut harus dilakukan secara eksplisit.

Hari
sumber
1

Selama program Anda mati, maka tanpa melepaskan atau bergabung dengan utas, kesalahan ini akan terjadi. Tanpa melepaskan dan menggabungkan utas, Anda harus memberikan putaran tanpa akhir setelah membuat utas.

int main(){

std::thread t(thread,1);

while(1){}

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

Menarik juga bahwa, setelah tidur atau berputar, utas dapat dilepas atau digabungkan. Selain itu dengan cara ini anda tidak mendapatkan error ini.

Contoh di bawah ini juga menunjukkan bahwa, thread ketiga tidak dapat melakukan tugasnya sebelum main die. Tapi kesalahan ini tidak bisa terjadi juga, selama Anda melepaskan kode di suatu tempat. Utas ketiga tidur selama 8 detik tetapi utas utama akan mati dalam 5 detik.

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;}
pengguna2908225
sumber
1

tahun, utas harus join (). saat keluar utama

yongyu wu
sumber
1
Jawaban ini mungkin lebih cocok untuk komentar yang dilampirkan pada jawaban lain. Dan saya harus mengatakan, selamat datang di Stack Overflow!
Contango
0

Pertama, Anda menentukan utas. Dan jika Anda tidak pernah memanggil join () atau detach () sebelum memanggil penghancur thread, program akan dibatalkan.

Sebagai berikut, memanggil destruktor thread tanpa terlebih dahulu memanggil join (menunggu sampai selesai) atau detach dijamin akan segera memanggil std :: terminate dan mengakhiri program.

Baik secara implisit melepaskan atau bergabung dengan thread joinable () di destruktornya dapat mengakibatkan kesulitan untuk men-debug bug kebenaran (untuk melepaskan) atau kinerja (untuk bergabung) yang ditemui hanya ketika pengecualian dimunculkan. Dengan demikian, programmer harus memastikan bahwa destruktor tidak pernah dijalankan saat utas masih dapat digabungkan.

Li Yingjun
sumber