2015-12-18 9 views
4

Я пытаюсь реализовать класс, который создает поток, увеличивает значение и отправляет его в другой поток, число которых определяется как (значение * значение)% число потоковошибка сегментации при создании потока

#include <iostream> 
#include <pthread.h> 
#include <unistd.h> 
#include <cstdlib> 
#include <vector> 

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cv = PTHREAD_COND_INITIALIZER; 
volatile int counter = 0; 
volatile int maxval = 0; 
volatile int next = 0; 

extern "C" void *func(void *p); 

class Worker { 
private: 
    pthread_t thread = 0; 
    int nth = 0; 
    int nproc = 0; 
public: 
    Worker() {}; 
    Worker(int _nproc, int _nth) { 
     nth = _nth; 
     nproc = _nproc; 
    }; 
    void start() { 
     pthread_create(&thread, NULL, func, NULL); // Line 27 

    }; 
    void wait() { 
     while (nth != next) { 
      pthread_cond_wait(&cv, &m); 
     } 
    }; 
    void notify() { 
     pthread_cond_broadcast(&cv); 
    }; 
    void run() { 
     while (counter != maxval) { 
      pthread_mutex_lock(&m); 
      Worker::wait(); 
      if (counter != maxval) { 
       printf("%d %d\n", nth, counter); 
       ++counter; 
      } 
      next = (counter * counter) % nproc; 
      Worker::notify(); 
      pthread_mutex_unlock(&m); 
     } 
    }; 
    void join() { 
     pthread_join(thread, NULL); 
    } 
}; 

extern "C" void *func(void *p) { 
    Worker *w = reinterpret_cast<Worker*>(p); 
    w->run(); 
    return NULL; 
} 

int main(int argc, char *argv[]) { 
    int nthreads = atoi(argv[1]); 
    maxval = atoi(argv[2]); 
    std::vector<Worker> workers; 
    for (int i = 0; i != nthreads; ++i) { 
     workers.push_back(Worker(nthreads, i)); 
    } 
    for (int i = 0; i != workers.size(); ++i) { 
     workers[i].start(); 
    } 
    for (int i = 0; i != workers.size(); ++i) { 
     workers[i].join(); 
    } 
    return 0; 
} 

Невозможно проверить, если алгоритм является правильным, так как я получаю Segmentation Ошибка когда я называю pthread_create (строка 27)

Это то, что GDB сказал:

#0 0x0000000000400f5a in Worker::wait (this=0x0) at ht19-4.cpp:30 
#1 0x0000000000400fd5 in Worker::run (this=0x0) at ht19-4.cpp:40 
#2 0x0000000000400d26 in func (p=0x0) at ht19-4.cpp:57 
#3 0x00007ffff76296aa in start_thread (arg=0x7ffff6f4f700) 
    at pthread_create.c:333 
#4 0x00007ffff735eeed in clone() 
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109 

Может ли кто-нибудь объяснить, что именно происходит в этой функции, пожалуйста? Как это реализовать правильно?

Большое спасибо.

+0

@EliasVanOotegem Я думаю, что это выше основного. –

+2

Основываясь на вашей трассировке стека, кажется, что ваш сбой внутри чего-то вызывает 'func()'. Запись 'Worker :: run (this = 0x0)' предполагает, что у вас есть неинициализированный указатель на объект; как вы его инициализируете? – mah

+2

Приятно видеть некоторые gdb в вопросе на C++. :) – erip

ответ

2

Вы отправлены func и не передаете NULL, а 4-й аргумент pthread_create - это то, что отправляется функцией в третьем аргументе.

Изменить func правильно обрабатывать NULL и вы должны быть хорошо:

extern "C" void *func(void *p) { 
    if (NULL == p) 
     return NULL; 
    Worker *w = reinterpret_cast<Worker*>(p); 
    w->run(); 
    return NULL; 
} 

Также +1 для размещения выход GdB так вот еще некоторая информация:

Если следовать вашей трассировки стека вверх (I мы вводим их в том порядке, в котором они происходят), мы видим, что func выполняет свою работу по кастингу и вызывает run на Worker, который он отличает от NULL. Обратите внимание на (p=0x0) и (this=0x0):

#2 0x0000000000400d26 in func (p=0x0) at ht19-4.cpp:57 
#1 0x0000000000400fd5 in Worker::run (this=0x0) at ht19-4.cpp:40 

Worker::run работает нормально, потому что она обращается только к counter, maxval и m доходя до Worker::wait()

#0 0x0000000000400f5a in Worker::wait (this=0x0) at ht19-4.cpp:30 

В Worker::wait() вы обращаетесь nth, который является членом нулевой Worker экземпляр, и вы, наконец, получите свой segfault.

+0

Да, это сделаю! – mah

2

Проблема заключается в создании потока, который вы передаете NULL для последнего аргумента.

pthread_create(&thread, NULL, func, NULL); 

Пока запускается поток он вызывает func() с NULL значением, переданным ему. Так внутри func()p is NULL, и вы пытаетесь выполнить бросок, а затем получить доступ к этому местоположению. Вот почему вы получаете ошибку сегментации.