Почему это вызывает ошибку сегмента? - PullRequest
1 голос
/ 07 марта 2012

Я работаю над заданием, связанным с многопоточностью и синхронизацией с pthreads.В примере кода основной поток создает два других потока, которые выполняются нормально.Основной поток блокируется до тех пор, пока оба этих «дочерних» потока не прекратятся.По крайней мере, так я это понимаю.Когда основной поток возобновляет выполнение, он, похоже, получает ошибку сегментации, когда вызывает деструктор для AvionicsTask.Честно говоря, я понятия не имею, почему, за исключением того, что я могу неправильно инициализировать что-то.В любом случае код выглядит следующим образом:

Task.h:

class Task {
protected:
    /* -- NAME */
    static const int MAX_NAME_LEN = 15;
    char name[MAX_NAME_LEN];

    /* -- IMPLEMENTATION */
    pthread_t thread_id;

public:
    /* -- CONSTRUCTOR/DESTRUCTOR */
    Task(const char _name[]) {

        std::strncpy(name, _name, MAX_NAME_LEN);
    }
    ~Task(){}
    /* -- ACCESSORS */
    char * Name();

    virtual void Start();    
    virtual void Run()= 0;
    static void GracefullyExitMainThread();
};

Task.cpp:

#include "task.h"

std::vector<pthread_t> tasklist;        //keep track of tasks created

void * thunkfunc(void * args) {
        Task * task_instance = (Task *)args;
        task_instance->Run();
        return NULL;
}

void Task::Start(){
    pthread_t threadmachine;
    void * start_arg = NULL;
    pthread_create(&threadmachine,  NULL, thunkfunc, this);
    tasklist.push_back(threadmachine);
}

void Task::GracefullyExitMainThread() {
    void** return_value;                //unused
    for(int i = 0; i < tasklist.size(); i++){
        pthread_join(tasklist[i], return_value);
    }
}

char * Task::Name(){
    return name; 
}

Task_Test_step1.cpp:

#include <iostream>
using namespace std;
#include "task.h"


class RudderController : public Task {
public:
  RudderController(char _name[]) : Task(_name) {}

  void Run() {
    cout << "Rudder Controller [" << name << "] running\n" << flush;
    for (int i = 0; i < 10; i++) {
      cout << name << " waiting for next sensor input\n" << flush;
      usleep(1000000);
      cout << name << " issueing rudder control command" << i << "\n" << flush;
      usleep(10000);
    }
  }
};

class AvionicsTask : public Task {
public:
  AvionicsTask(char _name[]) : Task(_name) {}

  void Run() {
    cout << "Avionics System [" << name << "] running\n" << flush;
    for (int i = 0; i < 10; i++) {
      cout << name << " waiting for next refresh interval\n" << flush;
      usleep(700000);
      cout << name << " refreshing avionics screen " << i << "\n" << flush;
      usleep(12000);
    }
  }
};

int main(int argc, char * argv[]) {

  /* -- CREATE TASKS */
  RudderController task1("rudder control");
  AvionicsTask     task2("avionics task");

  /* -- LAUNCH TASKS */
  task1.Start();
  task2.Start();

  Task::GracefullyExitMainThread();
}

вывод программы с помощью gdb:

Starting program: /home/ben/Desktop/Part 1/test 
[Thread debugging using libthread_db enabled]
[New Thread 0x7ffff707e700 (LWP 6797)]
Rudder Controller [rudder control] running
rudder control waiting for next sensor input
[New Thread 0x7ffff687d700 (LWP 6798)]
Avionics System [avionics task] running
avionics task waiting for next refresh interval
avionics task refreshing avionics screen 0
...
//more messages from the threads
...
avionics task refreshing avionics screen 9
[Thread 0x7ffff687d700 (LWP 6798) exited]
rudder control issueing rudder control command7
rudder control waiting for next sensor input
rudder control issueing rudder control command8
rudder control waiting for next sensor input
rudder control issueing rudder control command9
[Thread 0x7ffff707e700 (LWP 6797) exited]

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401ffa in AvionicsTask::~AvionicsTask (this=0xffffffffffffffc0, 
    __in_chrg=<optimized out>) at task_test_step1.cpp:21
21  class AvionicsTask : public Task {

1 Ответ

1 голос
/ 07 марта 2012

То, как вы используете return_value, неверно:

void** return_value;               
for(int i = 0; i < tasklist.size(); i++){
    pthread_join(tasklist[i], return_value); // <== return_value has an indeterminate value
                                             // who knows where pthread_join() will write to?
}

Просто введите NULL, если вас не интересует, что поток, к которому вы присоединяетесь, передает pthread_exit() (или, что эквивалентно, что возвращает функция потока):

for(int i = 0; i < tasklist.size(); i++){
    pthread_join(tasklist[i], NULL);   // <== ignore what the thread returns
}

Если вы когда-нибудь решите, что хотите получить значение, возвращаемое потоком, используйте что-то похожее на:

void* return_value;               
for(int i = 0; i < tasklist.size(); i++){
    pthread_join(tasklist[i], &return_value);

    // return_value contains the data the thread returned...
}
...