2010-08-24 86 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中,你都不需要函數調用周圍的外部函數。儘管我曾在一些編譯器中聽到過你。