2016-07-08 2 views
1

Я изучаю многопоточность на C++, используя pthread, на Tutorials Point (может быть, он старый, но мне просто нужно что-то начать). Я изменил код немного:Многопоточность C++: завершение после бросания экземпляра 'std :: length_error'

#include <pthread.h> 
#include <iostream> 
#include <string> 

#define NUM_THREADS 5 
#define DEBUG 
#undef DEBUG 

using namespace std; 

struct thread_data { 
    int thread_id = 0; 
    string message = ""; 
}; 

void *printHello(void *threadData) 
{ 
    struct thread_data* data = (struct thread_data*)threadData; 
    int thread_id = data->thread_id; 
    string message = data->message; 

    cout << "From thread " << thread_id << ": " << message << "\n"; 
    pthread_exit(NULL); 
} 

int main(int argc, char** argv) 
{ 
    pthread_t threads[NUM_THREADS]; 

    for (int i = 0; i < NUM_THREADS; i++) { 
     struct thread_data* data = new thread_data(); 
     string message = "Special message for thread #" + to_string(i) + "!"; 

     #ifdef DEBUG 
     cout << "DEBUG: " << "i = " << i << endl; 
     #endif 

     data->thread_id = i; 
     data->message = message; 

     cout << "main(): creating thread, " << i << endl; 
     int rc = 0; 
     rc = pthread_create(&threads[i], NULL, printHello, (void *) data); 

     delete data; 

     if (rc) { 
      cout << "Error: unable to create thread: " << rc << "\n"; 
      return -1; 
     } 
    } 

    pthread_exit(NULL);  
} 

Я скомпилированного:

g++ -pthread -g -Wall -std=c++11 main.cpp -o main 

И выход:

main(): creating thread, 0 
main(): creating thread, 1 
From thread 1: Special message for thread #1! 
main(): creating thread, 2 
From thread 2: Special message for thread #2! 
main(): creating thread, 3 
From thread 3: Special message for thread #3! 
main(): creating thread, 4 
From thread 4: Special message for thread #4! 
terminate called after throwing an instance of 'std::length_error' 
    what(): basic_string::_S_create 
Aborted (core dumped) 

Если я не создавать темы, используя pthread_create и вызов функция printHello напрямую, ошибки не возникает. Иногда программа запускает segfault вместо этого, и иногда она работает гладко!

Другая проблема заключается в том, что с самого начала должна быть строка, указывающая From thread 0: Special message for thread #0!, но не было.

Кроме того, иногда сообщение «Специальное сообщение для потока #n!» даже не появился.

Я попытался инициализировать переменные структуры, использовать статически выделенную память (стек вместо кучи, не используя new) в строке 31. Я попытался избежать использования указателей в функции printHello, но так как последний аргумент pthread_create принимает только указатель на аргументы функции, я не мог этого сделать.

Мое первое подозрение было в том, что есть что-то не так, когда я назначаю data->message = message, поэтому я попытался назначить строку непосредственно data->message, но не повезло. Но я все еще думаю, что ошибка должна быть там, поскольку исключение составляет std::length_error, брошенное «basic_string».

Или, может быть, когда я перехожу data в pthread_create или когда я делаю бросок по строке 18, я сделал что-то не так. Моя мысль заключается в том, что когда я передаю ее функции, я передаю ее в виде указателя, отбросив ее до указателя void void *. Когда printHello получил этот параметр, я произвел его на тип thread_data*, который является указателем, который является тем, чем он был первоначально.

Вот тогда я могу придумать до сих пор. Прошу прокомментировать, если что-то неясное в моем письме (английский не мой первый язык).

Спасибо всем заблаговременно.

ответ

2

Вы удаляете data сразу после создания темы. Это означает, что нет никакой гарантии, что указатель data по-прежнему указывает на живой объект к тому времени, когда поток попытается получить к нему доступ.

Вы должны удалить только data, когда никто не будет использовать этот объект. например. после завершения потока (вы можете использовать pthread_join для достижения этого, например.).

+0

Спасибо, в этом была проблема. Я присоединился к потоку перед вызовом delete, и он работал нормально. –

+0

@QuanTran: обратите внимание, что если вы присоединитесь к потоку внутри цикла for, вы не будете запускать свои потоки параллельно. Вы захотите присоединиться к потокам * после * цикла for (что также означает, что вам нужно будет отслеживать указатели данных за пределами цикла for). –

+0

Спасибо, я этого не замечал до сих пор.Я на самом деле изучил параллелизм в Java, написав диспетчер загрузки, но поскольку этот проект больше этого небольшого упражнения, я создал потоки и присоединил их к различным циклам, в то время как для этого небольшого упражнения я просто помещал их все в один цикл. Большое спасибо :) –

Смежные вопросы