Я написал образец программы, чтобы показать свою проблему - я не понимаю, почему firstVersion() работает правильно, а secondVersion() выдает ошибку: terminate called without an active exception Aborted. Спасибо за ответы! Вот код :)

#include <thread>
#include <iostream>
#include <chrono>

using namespace std;
const int threadCount = 100;
int N = 1;


void f() {
    N++;
}

void firstVersion() {
    thread * t[threadCount];
    for(int i = 0; i < threadCount; i++) {
        thread * ti = new thread{f};
        t[i] = ti;
    }
    for(int i = 0; i < threadCount; i++) {
        t[i]->join();
        delete t[i];
    }
}


void secondVersion() {
    thread * t[threadCount];
    for(int i = 0; i < threadCount; i++) {
        thread ti{f};
        t[i] = &ti;
    }
    for(int i = 0; i < threadCount; i++)
        t[i]->join();
}

int main() {
    //firstVersion();
    secondVersion();
    return 0;
}
0
delabania 27 Ноя 2016 в 17:15

2 ответа

Лучший ответ

Вторая версия терпит неудачу, потому что время жизни потока заканчивается в конце цикла for перед вызовом join().

void secondVersion() {
    thread * t[threadCount];
    for(int i = 0; i < threadCount; i++) {
        thread ti{f};        // local object of thread
        t[i] = &ti;
    }                        // the object dies without a join()

Ваш пример можно упростить как:

void SomeFunc() {}

int main()
{
    std::thread* tp; 
    //{ 
        std::thread t{SomeFunc};
        tp= &t; 
    //}   // if the closing brace is present, object t calls destructor here!

    tp->join();
}

Если вы посмотрите на свой STL, вы найдете следующий код:

~thread()
{   
  if (joinable())
std::terminate();
}

Это просто приводит к вызову terminate.

Итак, в примере кода есть две ошибки:

1) Создайте указатель на объект, который умирает до того, как будет использован указатель, который называется dangling reference

2) Поскольку объект потока умирает до вызова join (), он просто вызывает terminate.

2
Klaus 27 Ноя 2016 в 18:20

std::thread необходимо join или detach отредактировать до запуска его деструктора.

Поскольку вы не вызывали ни detach, ни join деструктор std::thread, названный std::abort.

В первом примере вы сначала join редактировали поток, прежде чем фактически вызвать его деструктор (через delete):

 t[i]->join();
 delete t[i];

К счастью для вас, это предотвратило гораздо худшее: висячие указатели. в конце каждого

 for(int i = 0; i < threadCount; i++) {
        thread ti{f};
        t[i] = &ti;
    }

ti мертв, вы сохраняете указатель на объект, который больше не существует. вы нарушаете какое-то основное правило C ++: никогда не возвращайте и не сохраняйте указатель или ссылку на локальную переменную вне ее области

2
David Haim 27 Ноя 2016 в 14:23