2010-08-24 22 views
13

Tôi đang cố gắng để hiểu một số vấn đề cơ bản của việc sử dụng POSIX pthreads. Loại điều tôi cần làm (cuối cùng) là song song một số tính toán, sử dụng mô hình hồ bơi luồng. Hiện tại tôi muốn đảm bảo rằng tôi có một ý nghĩa rất cơ bản về cách mô hình POSIX pthread hoạt động. Vì vậy, tôi đang cố gắng để tạo ra các hồ bơi thread đơn giản đó là đủ chung để làm những loại điều tôi muốn làm. Sẽ có một số bộ nhớ chia sẻ, một hàng đợi đầu vào, và một hàng đợi đầu ra, và sẽ có các mutexes bảo vệ mỗi. Tôi đã viết một số mã chỉ làm điều đó nhưng công cụ helgrind của valgrind không thích những gì tôi đã làm. Tôi nghi ngờ tôi đang thiếu một cái gì đó cơ bản. Bạn có hiểu biết sâu sắc về mã của tôi không?Một hồ bơi thread rất đơn giản sử dụng pthreads trong C++

#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); 
} 

Đây là đầu ra helgrind khi chuyển đối số 2 40 sang chương trình đã biên dịch.


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) 

Tôi không tự tin khi nói đến việc giải thích đầu ra helgrind.

Cảm ơn mọi thông tin chi tiết.

+2

+1 không chỉ cho chúng tôi mã mà còn mô tả thông báo lỗi. – wheaties

+2

Tôi không thấy gì sai. Có lẽ sai tích cực từ helgrind? – Starkey

+0

Được rồi, sau khi chơi đủ với đủ mã được viết bởi những người khác sử dụng pthreads thành công, có vẻ như rắc rối là helgrind chỉ đơn giản là đưa ra cách quá nhiều sai tích cực. –

Trả lời

1

Một số lỗi của bạn đến từ libgcc_s.so. Một số xuất hiện trong quá trình khởi tạo chuỗi, trước khi chức năng của bạn được gọi.

Thử biên dịch với gcc -pthread để đảm bảo trình biên dịch biết điều gì đang xảy ra.

+0

Đó là những gì tôi đang làm. Bạn không nhận được cùng một vấn đề nếu bạn chạy helgrind trên thực thi? –

+0

Tôi nhận thấy ứng dụng "pbzip2" sử dụng một nhóm luồng, nó cũng được viết theo kiểu C/C++ giống như mã của tôi. Helgrind chỉ có một khiếu nại khi pbzip2 đang chạy, nó giống như khiếu nại trên cùng trong đầu ra helgrind của tôi. Vì vậy, khiếu nại đó có lẽ không quan trọng lắm, nhưng những người khác tôi không biết ý của họ là gì. –

+0

@Ryan: Các lỗi khác đề cập đến 'pthread_once', được sử dụng để khởi tạo biến tĩnh. Ngoài ra, chúng ta biết chúng xảy ra trước vòng lặp trong công nhân. Vì điều thú vị duy nhất là tạo ra một 'stringstream' và một vài' string ', hãy thử xây dựng một' stringstream' giả và làm một cái gì đó tương tự trong 'main' trước' pthread_create', chỉ để khởi tạo các globals liên quan. Ngoài ra, nó có thể là đáng giá để thử các phiên bản khác nhau của trình biên dịch. – Potatoswatter

2

Tôi thiếu một khối "C" {} bên ngoài cho hàm chuỗi của bạn ít nhất, vì thư viện C sẽ mong đợi một C ABI. Ngoài ra, tôi không thể thấy bất cứ điều gì rõ ràng.

Ví dụ: tạo ra một nguyên mẫu như:

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

Bạn đang sử dụng một vòng lặp bận rộn:

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

    if (!somethingTodo) continue; 

nhìn lên biến điều kiện.
Bằng cách đó, luồng của bạn không tiêu tốn tài nguyên đang chờ công việc xuất hiện trong hàng đợi.
See this question

Bạn đã gắn thẻ câu hỏi C++ nhưng bạn đang sử dụng phôi kiểu C.
Cũng lưu ý rằng trong C++ bạn không cần thêm cấu trúc tại đây.

my_data = (struct thread_detail *) threadarg; 

Về mặt kỹ thuật, bạn nên khai báo các hàm callback của bạn để sử dụng C ABI (vì đây là một thư viện C.

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

sự lựa chọn cá nhân di chuyển * bên cạnh các loại (nhưng đó chỉ là pref cá nhân của tôi).

bạn đang không sử dụng RAII. Vì vậy khóa của bạn/mở khóa senarios không an toàn ngoại lệ.

pthread_mutex_lock(&inQueueLock); 

    // Stuff that could throw. 

    pthread_mutex_unlock(&inQueueLock); 

Ngay cả khi các công cụ ở giữa không thể ném ngay bây giờ. Bạn đang giả định rằng ai đó sẽ không thêm mã mà không ném trong tương lai. Làm cho nó an toàn bằng cách tạo ra một đối tượng khóa.

+0

Người dùng có tên "Dima" đã gắn thẻ câu hỏi là C++, không phải tôi. Về bình luận "busy loop", luồng công nhân chỉ được gọi nếu hàng đợi không rỗng, và một khi chuỗi công nhân trống rỗng của nó kết thúc. Vì vậy, nó không bao giờ lãng phí tài nguyên trên hàng đợi trống. Tôi nghĩ có lẽ bạn đang nghĩ rằng mã của tôi phức tạp hơn nó. Các hồ bơi thread công nhân chỉ bắt đầu khi có một công việc để làm, và sau đó nó bị giết. Điều này dường như không giải quyết được đầu ra của helgrind. Đánh giá từ phản hồi của mọi người cho đến nay là âm thanh như helgrind không cung cấp thông tin đáng tin cậy, ngay cả trên "tốt" mã pthread? –

+0

Về nhận xét sau của bạn về các cuộc gọi khóa/mở khóa mutex - hiện tại tôi chỉ muốn đảm bảo thử nghiệm độc lập này chạy đúng cách. Đây không phải là mã mà ai đó sẽ liên lạc. Tôi là một lập trình viên nghiệp dư. Tôi không sao không tuân thủ RAII. Đây chỉ là về tôi hiểu pthreads cho bây giờ. –

+1

@Ryan: Sẽ rõ ràng hơn khi nói 'if (! SomethingToDo) ngắt;' thay vì 'tiếp tục', vì' tiếp tục' dẫn ngay đến lối thoát vòng lặp. – Potatoswatter

1

Điều đó thực sự phụ thuộc vào trình biên dịch của bạn. Trong cả gnu và clang bạn không cần extern c xung quanh cuộc gọi hàm. Mặc dù tôi đã nghe trong một số trình biên dịch bạn làm.

Các vấn đề liên quan