【问题标题】:A very simple thread pool using pthreads in C++在 C++ 中使用 pthreads 的一个非常简单的线程池
【发布时间】:2011-04-03 10:19:52
【问题描述】:

我正在尝试了解使用 POSIX pthread 的一些基础知识。我需要做的事情(最终)是使用线程池模型并行化一些计算。目前我想确保我对 POSIX pthread 模型的工作原理有一个非常基本的了解。所以我正在尝试创建最简单的线程池,该线程池足够通用,可以做我想做的事情。将有一些共享内存、一个输入队列和一个输出队列,并且会有互斥锁保护它们。我已经编写了一些代码,但 valgrind 的 helmgrind 工具不喜欢我所做的。我怀疑我缺少一些基本的东西。您对我的代码有见解吗?

#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 传递给编译程序时的 helmgrind 输出。


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 (buildd@yellow) (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 (pthread_create@@GLIBC_2.2.5) redirected to 0x4c2d4c7 (pthread_create@*)
==12394== Thread #2 was created
==12394==    at 0x64276BE: clone (clone.S:77)
==12394==    by 0x555E172: pthread_create@@GLIBC_2.2.5 (createthread.c:75)
==12394==    by 0x4C2D42C: pthread_create_WRK (hg_intercepts.c:230)
==12394==    by 0x4C2D4CF: pthread_create@* (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: pthread_create@* (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: pthread_create@@GLIBC_2.2.5 (createthread.c:75)
==12394==    by 0x4C2D42C: pthread_create_WRK (hg_intercepts.c:230)
==12394==    by 0x4C2D4CF: pthread_create@* (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: pthread_create@* (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)

在解释 hlgrind 输出时,我不是那么自信。

感谢您的任何见解。

【问题讨论】:

  • +1 不仅为我们提供了代码,还为我们提供了错误消息的描述。
  • 我看不出有什么问题。可能是来自 helmgrind 的误报?
  • 好吧,在玩够了其他人编写的成功使用 pthreads 的代码之后,看来问题在于 helgrind 简单地给出了太多的误报。

标签: c++ pthreads posix threadpool


【解决方案1】:

这实际上取决于您的编译器。在 gnu 和 clang 中,你不需要函数调用周围的 extern c。虽然我在一些编译器中听说过你这样做。

【讨论】:

    【解决方案2】:

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

    尝试使用gcc -pthread 进行编译,以确保编译器知道发生了什么。

    【讨论】:

    • 这就是我正在做的。如果您在可执行文件上运行 hlgrind,您不会遇到同样的问题吗?
    • 我注意到应用程序“pbzip2”使用线程池,它也像我的代码一样以 C/C++ 风格编写。当 pbzip2 运行时,Helgrind 只有一个抱怨,这与我的 helgrind 输出中最重要的抱怨相同。所以那个抱怨也许不是那么重要,但其他的我不知道他们的意思。
    • @Ryan:其他错误提到pthread_once,它用于初始化静态变量。此外,我们知道它们发生在工人循环之前。因为唯一有趣的事情是创建一个stringstream 和一些strings,所以尝试构建一个虚拟stringstream 并在pthread_create 之前在main 中做类似的事情,只是为了初始化相关的全局变量。此外,尝试不同版本的编译器可能是值得的。
    • 我在家里使用 gcc 4.3.3(在 Ubuntu 10.04 下)。我在家里也安装了 gcc 4.2.4。两者都有同样的问题。在办公室计算机上,我安装了 4.4.3 和 4.3.4,两者都有同样的问题。还在办公室运行 Ubuntu 10.04。我在线程初始化之前消除了字符串流初始化和调用,而 valgrind 输出没有变化。我将尝试对线程初始化之前出现的其他内容进行类似的调整。
    • 我会尽快在一些非 Ubuntu(或至少非 10.04)系统上试用它。我可以访问的大多数其他系统都没有安装 valgrind。
    【解决方案3】:

    您正在使用繁忙的循环:

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

    个人选择将 * 移到类型旁边(但这只是我个人的偏好)。

    您没有使用 RAII。所以你的锁定/解锁场景不是异常安全的。

      pthread_mutex_lock( &inQueueLock );
    
      // Stuff that could throw.
    
      pthread_mutex_unlock( &inQueueLock );
    

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

    【讨论】:

    • 名为“Dima”的用户将问题标记为 C++,而不是我。关于“忙循环”注释,仅当队列非空时才调用工作线程,一旦为空,工作线程就会终止。所以它永远不会在空队列上浪费资源。我想也许你认为我的代码比它更复杂。工作线程池仅在有工作要做时才启动,然后被杀死。这似乎并没有解决 helmgrind 输出。从迄今为止人们的反馈来看,听起来 helgrind 没有提供可靠的信息,即使是“好的”pthread 代码?
    • 关于您后面对互斥锁/解锁调用的评论——现在我只想确保这个独立的实验正常运行。这不是其他人会触及的代码。我是一个业余程序员。我可以不遵守 RAII。这只是关于我现在对 pthread 的理解。
    • @Ryan:if ( ! somethingToDo ) break;continue 更清楚,因为continue 会立即导致循环退出。
    • @Ryan Budney:如果你最初是用 C 编写的,那么我会撤回所有的 cmets 并认为它对 C 程序有好处(虽然有点不整洁)。但我要强调 Potatoswatter 关于使用 continue 的观点。
    • 我把 continue 换成了 break。我仍然对为什么 helgrind 不喜欢这个程序感到困惑。感谢所有 cmets。
    【解决方案4】:

    我至少为您的线程函数缺少一个 extern "C" {} 块,因为 C 库需要一个 C ABI。除此之外,我看不到任何明显的东西。

    例如创建一个原型,如:

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

    【讨论】:

      猜你喜欢
      • 2012-07-05
      • 2011-05-09
      • 1970-01-01
      • 2012-06-16
      • 2014-04-12
      • 1970-01-01
      • 2012-03-23
      • 2011-10-20
      • 1970-01-01
      相关资源
      最近更新 更多