2010-08-24 120 views
13

我想了解一些使用POSIX pthreads的基础知识。我需要做的事情(最终)是使用线程池模型并行化一些计算。目前我想确保我对POSIX pthread模型的工作原理有一个非常基本的理解。所以我正在尝试创建最简单的线程池,这个线程池足以满足我想要做的事情。将会有一些共享内存,一个输入队列和一个输出队列,并且会有互斥体保护每一个。我写了一些代码,但valgrind的helgrind工具不喜欢我所做的。我怀疑我错过了一些基本的东西。你有没有对我的代码的见解?在C++中使用pthreads的非常简单的线程池

#include <stdlib.h> 
#include <string> 
#include <sstream> 
#include <list> 
#include <iostream> 

#include <pthread.h> 
#include <signal.h> 
#include <sys/select.h> 

// the muticies, protectors of the shared resources 
pthread_mutex_t coutLock; 
pthread_mutex_t inQueueLock; 
pthread_mutex_t outQueueLock; 
// the shared data 
std::list<std::string> inQueue; 
std::list<std::string> outQueue; 

struct thread_detail { // information to pass to worker threads 
unsigned long num; 
}; 

extern "C" { 
    void *workerThread(void *threadarg); 
} 

void *workerThread(void *threadarg) 
{ 
    struct thread_detail *my_data; 
    my_data = (thread_detail *) threadarg; 
    int taskid = my_data->num; 
    std::stringstream ss; ss<<taskid; std::string taskString(ss.str()); 

    bool somethingTodo=true; 
    while (somethingTodo) // keep on working until inQueue is empty 
    { 
     pthread_mutex_lock(&inQueueLock); 
     std::string workOnMe; 
     if (inQueue.size()==0) { somethingTodo=false; } 
     else 
     { 
     workOnMe = inQueue.front(); 
     inQueue.pop_front(); 
     } 
     pthread_mutex_unlock(&inQueueLock); 

     if (!somethingTodo) break; 
     workOnMe = "thread " + taskString + " worked on " + workOnMe; 
     // let's pretend this takes some time, add a delay to the computation 
     struct timeval timeout; 
     timeout.tv_sec = 0; timeout.tv_usec = 100000; // 0.1 second delay 
     select(0, NULL, NULL, NULL, & timeout); 

     pthread_mutex_lock(&outQueueLock); 
     outQueue.push_back(workOnMe); 
     pthread_mutex_unlock(&outQueueLock); 
    } 

    pthread_exit(NULL); 
} 


int main (int argc, char *argv[]) 
{ 
    unsigned long comp_DONE=0; 
    unsigned long comp_START=0; 
    // set-up the mutexes 
    pthread_mutex_init(&coutLock, NULL); 
    pthread_mutex_init(&inQueueLock, NULL); 
    pthread_mutex_init(&outQueueLock, NULL); 

    if (argc != 3) { std::cout<<"Program requires two arguments: (1) number of threads to use," 
          " and (2) tasks to accomplish.\n"; exit(1); } 
    unsigned long NUM_THREADS(atoi(argv[1])); 
    unsigned long comp_TODO(atoi(argv[2])); 
    std::cout<<"Program will have "<<NUM_THREADS<<" threads, working on "<<comp_TODO<<" things \n"; 
    for (unsigned long i=0; i<comp_TODO; i++) // fill inQueue will rubbish data since this isn't an actual computation... 
    { 
    std::stringstream ss; 
    ss<<"task "<<i; 
    inQueue.push_back(ss.str()); 
    } 

    // start the worker threads 
    std::list< pthread_t* > threadIdList; // just the thread ids 
    std::list<thread_detail> thread_table; // for keeping track of information on the various threads we'll create 
    for (unsigned long i=0; i<NUM_THREADS; i++) // start the threads 
    { 
    pthread_t *tId(new pthread_t); threadIdList.push_back(tId); 
    thread_detail Y; Y.num=i; thread_table.push_back(Y); 
    int rc(pthread_create(tId, NULL, workerThread, (void *)(&(thread_table.back())))); 
    if (rc) { std::cout<<"ERROR; return code from pthread_create() "<<comp_START<<"\n"; std::cout.flush(); 
       exit(-1); } 
    } 
    // now we wait for the threads to terminate, perhaps updating the screen with info as we go. 
    std::string stringOut; 
    while (comp_DONE != comp_TODO) 
    { 
     // poll the queue to get a status update on computation 
     pthread_mutex_lock(&inQueueLock); 
     comp_START = comp_TODO - inQueue.size(); 
     pthread_mutex_unlock(&inQueueLock); 
     pthread_mutex_lock(&outQueueLock); 
     comp_DONE = outQueue.size(); 
     pthread_mutex_unlock(&outQueueLock); 

     // update for users 
     pthread_mutex_lock(&coutLock); 
     for (unsigned long i=0; i<stringOut.length(); i++) std::cout<<"\b"; 
     std::stringstream ss; ss<<"started "<<comp_START<<" completed "<<comp_DONE<<" of "<<comp_TODO; 
     stringOut = ss.str(); std::cout<<stringOut; std::cout.flush(); 
     pthread_mutex_unlock(&coutLock); 

     // wait one second per update 
     struct timeval timeout; 
     timeout.tv_sec = 1; timeout.tv_usec = 0; 
     select(0, NULL, NULL, NULL, & timeout); 
     } // big while loop 

    // call join to kill all worker threads 
    std::list< pthread_t* >::iterator i(threadIdList.begin()); 
    while (i!=threadIdList.end()) 
    { 
    if (pthread_join(*(*i), NULL)!=0) { std::cout<<"Thread join error!\n"; exit(1); } 
    delete (*i); 
    threadIdList.erase(i++); 
    } 
    std::cout<<"\n"; 

    // let the user know what happened 
    for (std::list<std::string>::iterator i=outQueue.begin(); i!=outQueue.end(); i++) 
    { 
    std::cout<<(*i)<<"\n"; 
    } 
    // clean-up 
    pthread_mutex_destroy(&coutLock); 
    pthread_mutex_destroy(&inQueueLock); 
    pthread_mutex_destroy(&outQueueLock); 
    // pthread_exit(NULL); 
} 

这是将参数2 40传递给编译程序时的helgrind输出。


valgrind -v --tool=helgrind ./thread1 2 40 
==12394== Helgrind, a thread error detector 
==12394== Copyright (C) 2007-2009, and GNU GPL'd, by OpenWorks LLP et al. 
==12394== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info 
==12394== Command: ./thread1 2 40 
==12394== 
--12394-- Valgrind options: 
--12394-- --suppressions=/usr/lib/valgrind/debian-libc6-dbg.supp 
--12394-- -v 
--12394-- --tool=helgrind 
--12394-- Contents of /proc/version: 
--12394-- Linux version 2.6.32-24-generic ([email protected]) (gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)) #38-Ubuntu SMP Mon Jul 5 09:20:59 UTC 2010 
--12394-- Arch and hwcaps: AMD64, amd64-sse3-cx16 
--12394-- Page sizes: currently 4096, max supported 4096 
--12394-- Valgrind library directory: /usr/lib/valgrind 
--12394-- Reading syms from /home/rybu/prog/regina/exercise/thread1 (0x400000) 
--12394-- Reading syms from /lib/ld-2.11.1.so (0x4000000) 
--12394-- Reading debug info from /lib/ld-2.11.1.so .. 
--12394-- .. CRC mismatch (computed 99d13f6f wanted 0962e544) 
--12394-- Reading debug info from /usr/lib/debug/lib/ld-2.11.1.so .. 
--12394-- Reading syms from /usr/lib/valgrind/helgrind-amd64-linux (0x38000000) 
--12394-- object doesn't have a dynamic symbol table 
--12394-- Reading suppressions file: /usr/lib/valgrind/debian-libc6-dbg.supp 
--12394-- Reading suppressions file: /usr/lib/valgrind/default.supp 
--12394-- Reading syms from /usr/lib/valgrind/vgpreload_core-amd64-linux.so (0x4a23000) 
--12394-- Reading syms from /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so (0x4c25000) 
--12394-- REDIR: 0x4018310 (index) redirected to 0x4c2be59 (index) 
--12394-- REDIR: 0x4018390 (strcmp) redirected to 0x4c2bf4b (strcmp) 
--12394-- REDIR: 0x40184a0 (strlen) redirected to 0x4c2bec5 (strlen) 
--12394-- Reading syms from /usr/lib/libregina-engine-4.6.1.so (0x4e31000) 
--12394-- Reading syms from /usr/lib/libgmp.so.3.5.2 (0x52f7000) 
--12394-- Reading debug info from /usr/lib/libgmp.so.3.5.2 .. 
--12394-- .. CRC mismatch (computed d65050b9 wanted 1e40f6c0) 
--12394-- object doesn't have a symbol table 
--12394-- Reading syms from /lib/libpthread-2.11.1.so (0x5557000) 
--12394-- Reading debug info from /lib/libpthread-2.11.1.so .. 
--12394-- .. CRC mismatch (computed 9da7e2f6 wanted 8161fac5) 
--12394-- Reading debug info from /usr/lib/debug/lib/libpthread-2.11.1.so .. 
--12394-- Reading syms from /lib/librt-2.11.1.so (0x5774000) 
--12394-- Reading debug info from /lib/librt-2.11.1.so .. 
--12394-- .. CRC mismatch (computed 0e4f4ece wanted 920c9bed) 
--12394-- Reading debug info from /usr/lib/debug/lib/librt-2.11.1.so .. 
--12394-- Reading syms from /lib/libz.so.1.2.3.3 (0x597c000) 
--12394-- Reading debug info from /lib/libz.so.1.2.3.3 .. 
--12394-- .. CRC mismatch (computed 86f1fa27 wanted 5f1ca823) 
--12394-- object doesn't have a symbol table 
--12394-- Reading syms from /usr/lib/libstdc++.so.6.0.13 (0x5b93000) 
--12394-- Reading debug info from /usr/lib/libstdc++.so.6.0.13 .. 
--12394-- .. CRC mismatch (computed 7b5bd5a5 wanted e2f63673) 
--12394-- object doesn't have a symbol table 
--12394-- Reading syms from /lib/libm-2.11.1.so (0x5ea7000) 
--12394-- Reading debug info from /lib/libm-2.11.1.so .. 
--12394-- .. CRC mismatch (computed 043548c3 wanted a081b93d) 
--12394-- Reading debug info from /usr/lib/debug/lib/libm-2.11.1.so .. 
--12394-- Reading syms from /lib/libgcc_s.so.1 (0x612a000) 
--12394-- Reading debug info from /lib/libgcc_s.so.1 .. 
--12394-- .. CRC mismatch (computed 7c01dfc9 wanted 9d78e511) 
--12394-- object doesn't have a symbol table 
--12394-- Reading syms from /lib/libc-2.11.1.so (0x6341000) 
--12394-- Reading debug info from /lib/libc-2.11.1.so .. 
--12394-- .. CRC mismatch (computed c73d5a83 wanted 02758e3e) 
--12394-- Reading debug info from /usr/lib/debug/lib/libc-2.11.1.so .. 
--12394-- Reading syms from /usr/lib/libxml2.so.2.7.6 (0x66c4000) 
--12394-- Reading debug info from /usr/lib/libxml2.so.2.7.6 .. 
--12394-- .. CRC mismatch (computed c2590bed wanted 7aaa27a0) 
--12394-- Reading debug info from /usr/lib/debug/usr/lib/libxml2.so.2.7.6 .. 
--12394-- Reading syms from /lib/libdl-2.11.1.so (0x6a14000) 
--12394-- Reading debug info from /lib/libdl-2.11.1.so .. 
--12394-- .. CRC mismatch (computed 4a29f474 wanted e0b8d72c) 
--12394-- Reading debug info from /usr/lib/debug/lib/libdl-2.11.1.so .. 
--12394-- REDIR: 0x55603c0 (pthread_mutex_lock) redirected to 0x4c299fb (pthread_mutex_lock) 
--12394-- REDIR: 0x5561a00 (pthread_mutex_unlock) redirected to 0x4c29e8c (pthread_mutex_unlock) 
--12394-- REDIR: 0x63bd520 (malloc) redirected to 0x4c28a06 (malloc) 
--12394-- REDIR: 0x63bf360 (calloc) redirected to 0x4c27cc9 (calloc) 
--12394-- REDIR: 0x5c5e380 (operator new[](unsigned long)) redirected to 0x4c28e97 (operator new[](unsigned long)) 
--12394-- REDIR: 0x5c5e250 (operator new(unsigned long)) redirected to 0x4c2921f (operator new(unsigned long)) 
--12394-- REDIR: 0x5c5c380 (operator delete(void*)) redirected to 0x4c28328 (operator delete(void*)) 
--12394-- REDIR: 0x5c5c3c0 (operator delete[](void*)) redirected to 0x4c27fa4 (operator delete[](void*)) 
--12394-- REDIR: 0x63c3fe0 (strlen) redirected to 0x4a235dc (_vgnU_ifunc_wrapper) 
--12394-- REDIR: 0x63c4010 (__GI_strlen) redirected to 0x4c2be91 (strlen) 
--12394-- REDIR: 0x63c7c60 (memcpy) redirected to 0x4c2bfdb (memcpy) 
Program will have 2 threads, working on 40 things 
--12394-- REDIR: 0x555dd60 ([email protected]@GLIBC_2.2.5) redirected to 0x4c2d4c7 ([email protected]*) 
==12394== Thread #2 was created 
==12394== at 0x64276BE: clone (clone.S:77) 
==12394== by 0x555E172: [email protected]@GLIBC_2.2.5 (createthread.c:75) 
==12394== by 0x4C2D42C: pthread_create_WRK (hg_intercepts.c:230) 
==12394== by 0x4C2D4CF: [email protected]* (hg_intercepts.c:257) 
==12394== by 0x401C22: main (in /home/rybu/prog/regina/exercise/thread1) 
==12394== 
==12394== Thread #1 is the program's root thread 
==12394== 
==12394== Possible data race during write of size 8 at 0x7fefffcf0 by thread #2 
==12394== at 0x4C2D54C: mythread_wrapper (hg_intercepts.c:200) 
==12394== This conflicts with a previous read of size 8 by thread #1 
==12394== at 0x4C2D440: pthread_create_WRK (hg_intercepts.c:235) 
==12394== by 0x4C2D4CF: [email protected]* (hg_intercepts.c:257) 
==12394== by 0x401C22: main (in /home/rybu/prog/regina/exercise/thread1) 
==12394== 
started 21 completed 19 of 40==12394== Thread #3 was created 
==12394== at 0x64276BE: clone (clone.S:77) 
==12394== by 0x555E172: [email protected]@GLIBC_2.2.5 (createthread.c:75) 
==12394== by 0x4C2D42C: pthread_create_WRK (hg_intercepts.c:230) 
==12394== by 0x4C2D4CF: [email protected]* (hg_intercepts.c:257) 
==12394== by 0x401C22: main (in /home/rybu/prog/regina/exercise/thread1) 
==12394== 
==12394== Possible data race during read of size 1 at 0x63401a7 by thread #3 
==12394== at 0x613A4D7: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A947: _Unwind_Resume (in /lib/libgcc_s.so.1) 
==12394== by 0x4019C9: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== by 0x555D9C9: start_thread (pthread_create.c:300) 
==12394== by 0x64276FC: clone (clone.S:112) 
==12394== This conflicts with a previous write of size 1 by thread #2 
==12394== at 0x6138331: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x5563F42: pthread_once (pthread_once.S:104) 
==12394== by 0x613A4C9: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A7B6: _Unwind_ForcedUnwind (in /lib/libgcc_s.so.1) 
==12394== by 0x556508F: __pthread_unwind (unwind.c:130) 
==12394== by 0x555EEB4: pthread_exit (pthreadP.h:265) 
==12394== by 0x40198E: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== 
==12394== Possible data race during read of size 1 at 0x63401a6 by thread #3 
==12394== at 0x6139A12: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x6139AA8: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A724: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A982: _Unwind_Resume (in /lib/libgcc_s.so.1) 
==12394== by 0x4019C9: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== by 0x555D9C9: start_thread (pthread_create.c:300) 
==12394== by 0x64276FC: clone (clone.S:112) 
==12394== This conflicts with a previous write of size 1 by thread #2 
==12394== at 0x613832A: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x5563F42: pthread_once (pthread_once.S:104) 
==12394== by 0x613A4C9: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A7B6: _Unwind_ForcedUnwind (in /lib/libgcc_s.so.1) 
==12394== by 0x556508F: __pthread_unwind (unwind.c:130) 
==12394== by 0x555EEB4: pthread_exit (pthreadP.h:265) 
==12394== by 0x40198E: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== 
==12394== Possible data race during read of size 1 at 0x63401b0 by thread #3 
==12394== at 0x6139AD7: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A724: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A982: _Unwind_Resume (in /lib/libgcc_s.so.1) 
==12394== by 0x4019C9: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== by 0x555D9C9: start_thread (pthread_create.c:300) 
==12394== by 0x64276FC: clone (clone.S:112) 
==12394== This conflicts with a previous write of size 1 by thread #2 
==12394== at 0x6138370: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x5563F42: pthread_once (pthread_once.S:104) 
==12394== by 0x613A4C9: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A7B6: _Unwind_ForcedUnwind (in /lib/libgcc_s.so.1) 
==12394== by 0x556508F: __pthread_unwind (unwind.c:130) 
==12394== by 0x555EEB4: pthread_exit (pthreadP.h:265) 
==12394== by 0x40198E: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== 
--12394-- REDIR: 0x63bede0 (free) redirected to 0x4c28616 (free) 
started 40 completed 40 of 40--12394-- REDIR: 0x555ef30 (pthread_join) redirected to 0x4c29796 (pthread_join) 

thread 0 worked on task 0 
thread 1 worked on task 1 
thread 0 worked on task 2 
thread 1 worked on task 3 
thread 0 worked on task 4 
thread 1 worked on task 5 
thread 0 worked on task 6 
thread 1 worked on task 7 
thread 0 worked on task 8 
thread 1 worked on task 9 
thread 0 worked on task 10 
thread 1 worked on task 11 
thread 0 worked on task 12 
thread 1 worked on task 13 
thread 0 worked on task 14 
thread 1 worked on task 15 
thread 0 worked on task 16 
thread 1 worked on task 17 
thread 0 worked on task 18 
thread 1 worked on task 19 
thread 0 worked on task 20 
thread 1 worked on task 21 
thread 0 worked on task 22 
thread 1 worked on task 23 
thread 0 worked on task 24 
thread 1 worked on task 25 
thread 0 worked on task 26 
thread 1 worked on task 27 
thread 0 worked on task 28 
thread 1 worked on task 29 
thread 0 worked on task 30 
thread 1 worked on task 31 
thread 0 worked on task 32 
thread 1 worked on task 33 
thread 0 worked on task 34 
thread 1 worked on task 35 
thread 0 worked on task 36 
thread 1 worked on task 37 
thread 0 worked on task 38 
thread 1 worked on task 39 
==12394== 
==12394== ERROR SUMMARY: 7 errors from 4 contexts (suppressed: 804 from 64) 
==12394== 
==12394== 1 errors in context 1 of 4: 
==12394== Possible data race during read of size 1 at 0x63401a7 by thread #3 
==12394== at 0x613A4D7: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A947: _Unwind_Resume (in /lib/libgcc_s.so.1) 
==12394== by 0x4019C9: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== by 0x555D9C9: start_thread (pthread_create.c:300) 
==12394== by 0x64276FC: clone (clone.S:112) 
==12394== This conflicts with a previous write of size 1 by thread #2 
==12394== at 0x6138331: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x5563F42: pthread_once (pthread_once.S:104) 
==12394== by 0x613A4C9: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A7B6: _Unwind_ForcedUnwind (in /lib/libgcc_s.so.1) 
==12394== by 0x556508F: __pthread_unwind (unwind.c:130) 
==12394== by 0x555EEB4: pthread_exit (pthreadP.h:265) 
==12394== by 0x40198E: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== 
==12394== 
==12394== 2 errors in context 2 of 4: 
==12394== Possible data race during read of size 1 at 0x63401b0 by thread #3 
==12394== at 0x6139AD7: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A724: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A982: _Unwind_Resume (in /lib/libgcc_s.so.1) 
==12394== by 0x4019C9: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== by 0x555D9C9: start_thread (pthread_create.c:300) 
==12394== by 0x64276FC: clone (clone.S:112) 
==12394== This conflicts with a previous write of size 1 by thread #2 
==12394== at 0x6138370: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x5563F42: pthread_once (pthread_once.S:104) 
==12394== by 0x613A4C9: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A7B6: _Unwind_ForcedUnwind (in /lib/libgcc_s.so.1) 
==12394== by 0x556508F: __pthread_unwind (unwind.c:130) 
==12394== by 0x555EEB4: pthread_exit (pthreadP.h:265) 
==12394== by 0x40198E: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== 
==12394== 
==12394== 2 errors in context 3 of 4: 
==12394== Possible data race during read of size 1 at 0x63401a6 by thread #3 
==12394== at 0x6139A12: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x6139AA8: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A724: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A982: _Unwind_Resume (in /lib/libgcc_s.so.1) 
==12394== by 0x4019C9: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== by 0x555D9C9: start_thread (pthread_create.c:300) 
==12394== by 0x64276FC: clone (clone.S:112) 
==12394== This conflicts with a previous write of size 1 by thread #2 
==12394== at 0x613832A: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x5563F42: pthread_once (pthread_once.S:104) 
==12394== by 0x613A4C9: ??? (in /lib/libgcc_s.so.1) 
==12394== by 0x613A7B6: _Unwind_ForcedUnwind (in /lib/libgcc_s.so.1) 
==12394== by 0x556508F: __pthread_unwind (unwind.c:130) 
==12394== by 0x555EEB4: pthread_exit (pthreadP.h:265) 
==12394== by 0x40198E: workerThread(void*) (in /home/rybu/prog/regina/exercise/thread1) 
==12394== by 0x4C2D558: mythread_wrapper (hg_intercepts.c:202) 
==12394== 
==12394== 
==12394== 2 errors in context 4 of 4: 
==12394== Possible data race during write of size 8 at 0x7fefffcf0 by thread #2 
==12394== at 0x4C2D54C: mythread_wrapper (hg_intercepts.c:200) 
==12394== This conflicts with a previous read of size 8 by thread #1 
==12394== at 0x4C2D440: pthread_create_WRK (hg_intercepts.c:235) 
==12394== by 0x4C2D4CF: [email protected]* (hg_intercepts.c:257) 
==12394== by 0x401C22: main (in /home/rybu/prog/regina/exercise/thread1) 
==12394== 
--12394-- 
--12394-- used_suppression: 610 helgrind-glibc2X-101 
--12394-- used_suppression: 192 helgrind---...-*Unwind*-*pthread_unwind* 
--12394-- used_suppression:  2 helgrind-glibc2X-112 
==12394== 
==12394== ERROR SUMMARY: 7 errors from 4 contexts (suppressed: 804 from 64) 

当谈到解释helgrind输出时,我并不那么自信。

感谢您的任何见解。

+2

+1不仅为我们提供了代码,还提供了错误消息的描述。 – wheaties 2010-08-24 21:17:33

+2

我没有看到任何错误。也许从helgrind的误报? – Starkey 2010-08-24 21:31:32

+0

好了,在用足够的代码编写足够的代码后,其他人使用pthreads成功完成后,看起来麻烦是helgrind只是提供了太多的误报。 – 2010-08-27 19:57:20

回答

1

您的几个错误来自libgcc_s.so。其中一些似乎在线程初始化期间发生,甚至在你的函数被调用之前。

尝试编译gcc -pthread以确保编译器知道发生了什么。

+0

这就是我正在做的。如果你在可执行文件上运行helgrind,你难道不会遇到同样的问题吗? – 2010-08-24 23:04:42

+0

我注意到应用程序“pbzip2”使用线程池,它也是用我的代码编写的C/C++风格。当pbzip2运行时,Helgrind只有一个投诉,这与我的helgrind输出中的最高投诉相同。所以这个抱怨可能不是那么重要,但其他人我不知道他们的意思。 – 2010-08-25 02:48:50

+0

@Ryan:其他错误提到'pthread_once',它用于初始化静态变量。另外,我们知道它们发生在工人循环之前。由于唯一有趣的事情是创建了'stringstream'和一些'string's,试着在'pthread_create'之前建立一个虚拟'stringstream'并在main中做类似的事情,以初始化相关的全局变量。另外,尝试编译器的不同版本可能是值得的。 – Potatoswatter 2010-08-25 04:34:50

2

因为C库会期望C ABI,所以我至少错过了一个extern“C”{}块的线程函数。除此之外,我看不出任何明显的东西。

E.g.创建一个原型,如:

extern "C" { 
    void *workerThread(void *threadarg); 
} 
6

您使用的是繁忙的循环:

if (inQueue.size()==0) { somethingTodo=false; } 
    else 
    { 
    workOnMe = inQueue.front(); 
    inQueue.pop_front(); 
    } 
    pthread_mutex_unlock(&inQueueLock); 

    if (!somethingTodo) continue; 

查找条件变量。
这样你的线程就不会消耗等待工作出现在队列中的资源。
See this question

您标记了C++的问题,但您使用的是C风格转换。
另请注意,在C++中,您不需要在此添加结构。

my_data = (struct thread_detail *) threadarg; 

从技术上讲,你应该申报使用C ABI(因为这是一个C库回调函数。

extern "C" void *workerThread(void *threadarg); 

个人选择移动*旁边的类型(不过,这只是我个人的PREF )。

您没有使用RAII。所以,你的锁定/解锁senarios不例外安全。

pthread_mutex_lock(&inQueueLock); 

    // Stuff that could throw. 

    pthread_mutex_unlock(&inQueueLock); 

即使中间的东西现在也不能扔。你假设有人不会添加那些未来不会抛出的代码。通过创建一个锁对象来保证安全。

+0

名为“Dima”的用户将问题标记为C++,而不是我。关于“繁忙循环”注释,只有在队列非空时工作线程才会被调用,并且一旦工作线程终止,该线程将一直为空。所以它绝不会浪费空闲队列上的资源。我想也许你认为我的代码比现在更复杂。工作者线程池只在有工作要做时启动,然后被杀死。这似乎没有解决helgrind输出。从目前为止人们的反馈来看,听起来像helgrind并没有提供可靠的信息,即使是“好”的pthread代码? – 2010-08-24 22:27:57

+0

关于你对互斥锁/解锁调用的后面的评论 - 现在我只想确保这个独立实验正常运行。这不是别人会碰到的代码。我是一名业余程序员。我很好,不遵守RAII。这仅仅是关于我现在对pthreads的理解。 – 2010-08-24 22:36:13

+1

@Ryan:说'如果(!somethingToDo)break;'而不是'continue',会更清楚,因为continue会立即导致循环退出。 – Potatoswatter 2010-08-24 22:41:14

1

这实际上取决于你的编译器。在gnu和clang中,你都不需要函数调用周围的外部函数。尽管我曾在一些编译器中听到过你。