【问题标题】:pthread function from a class类中的 pthread 函数
【发布时间】:2010-11-12 04:51:16
【问题描述】:

假设我有一个类,例如

class c { 
    // ...
    void *print(void *){ cout << "Hello"; }
}

然后我有一个 c 向量

vector<c> classes; pthread_t t1;
classes.push_back(c());
classes.push_back(c());

现在,我想在c.print();上创建一个线程

以下是给我以下问题:pthread_create(&amp;t1, NULL, &amp;c[0].print, NULL);

错误输出:无法将 'void* (tree_item::)(void)' 转换为 'void* ()(void)' 用于参数 '3' 到 'int pthread_create(pthread_t*, const pthread_attr_t*, void* ()(void), void*)'

【问题讨论】:

    标签: c++ pthreads


    【解决方案1】:

    您必须为pthread_create 提供一个与其正在寻找的签名相匹配的函数。你传递的东西是行不通的。

    您可以实现任何您喜欢的静态函数,它可以引用c 的实例并在线程中执行您想要的。 pthread_create 的设计不仅是一个函数指针,而且是一个指向“上下文”的指针。在这种情况下,您只需将指针传递给c 的实例即可。

    例如:

    static void* execute_print(void* ctx) {
        c* cptr = (c*)ctx;
        cptr->print();
        return NULL;
    }
    
    
    void func() {
    
        ...
    
        pthread_create(&t1, NULL, execute_print, &c[0]);
    
        ...
    }
    

    【讨论】:

    • ooo 我明白你的意思了.. 将 c 的指针传递给它,得到了.. 将实现并尝试一下
    【解决方案2】:

    我的猜测是这是 b/c,它被 C++ b/c 弄乱了一点,你向它发送一个 C++ 指针,而不是一个 C 函数指针。显然有一个difference。尝试做一个

    (void)(*p)(void) = ((void) *(void)) &c[0].print; //(check my syntax on that cast)
    

    然后发送 p。

    我也用成员函数完成了你所做的事情,但我是在使用它的类中完成的,并且使用 static 函数 - 我认为这有所不同。

    【讨论】:

    • 我尝试了上述方法,但它给了我语法错误.. 也试图改变它......如果你愿意证明使用 pthread_create(...) 它可能是有帮助
    【解决方案3】:

    我最喜欢处理线程的方法是将其封装在 C++ 对象中。这是一个例子:

    class MyThreadClass
    {
    public:
       MyThreadClass() {/* empty */}
       virtual ~MyThreadClass() {/* empty */}
    
       /** Returns true if the thread was successfully started, false if there was an error starting the thread */
       bool StartInternalThread()
       {
          return (pthread_create(&_thread, NULL, InternalThreadEntryFunc, this) == 0);
       }
    
       /** Will not return until the internal thread has exited. */
       void WaitForInternalThreadToExit()
       {
          (void) pthread_join(_thread, NULL);
       }
    
    protected:
       /** Implement this method in your subclass with the code you want your thread to run. */
       virtual void InternalThreadEntry() = 0;
    
    private:
       static void * InternalThreadEntryFunc(void * This) {((MyThreadClass *)This)->InternalThreadEntry(); return NULL;}
    
       pthread_t _thread;
    };
    

    要使用它,您只需创建 MyThreadClass 的子类,并实现 InternalThreadEntry() 方法来包含线程的事件循环。当然,在删除线程对象之前,您需要在线程对象上调用 WaitForInternalThreadToExit() (并且有一些机制来确保线程实际退出,否则 WaitForInternalThreadToExit() 将永远不会返回)

    【讨论】:

    • 这是一个很好的方式,我可以理解上述虚拟类的使用,但我有很多更深层次的问题..我有线程会产生其他需要全部放入向量中的线程。然后是一个递归循环去加入所有线程。我确定我也可以通过在适当的地方调用等待来实现上述操作,但我会尝试看看我要去哪里
    • 这个解决方案非常优雅。从现在开始我会使用它。谢谢杰里米弗里斯纳。 +1
    • 你好 Jeremy Friesner,如何传递对 InternalThreadEntry(aclass_ref& refobj) 的引用?我应该做出哪些改变?
    • @sree 添加对 MyThreadClass 的引用(或指针)作为成员变量;然后 InternalThreadEntry() 可以直接访问它,而不必担心通过 (void *) 参数传递它。
    【解决方案4】:

    你不能按照你写的那样做,因为 C++ 类成员函数有一个隐藏的 this 参数传入。pthread_create() 不知道要使用 this 的什么值,所以如果你尝试通过将方法转换为适当类型的函数指针来绕过编译器,您将遇到分段错误。您必须使用静态类方法(没有this 参数)或普通函数来引导类:

    class C
    {
    public:
        void *hello(void)
        {
            std::cout << "Hello, world!" << std::endl;
            return 0;
        }
    
        static void *hello_helper(void *context)
        {
            return ((C *)context)->hello();
        }
    };
    ...
    C c;
    pthread_t t;
    pthread_create(&t, NULL, &C::hello_helper, &c);
    

    【讨论】:

    • 上述方法是否可以通过以下方式处理向量:pthread_create(&t, NULL, &C::hello_helper, &vector_c[0]); ?
    • 以上所有 cmets 都很有用,我使用了所有的组合来解决问题。它仍然像我尝试做的那样简单......但不幸的是,我只能将一个标记为是正确的,否则每个人都会得到荣誉..谢谢
    • 我想赞成这个答案,但它使用 C 风格的演员表,必须以极端的偏见终止。这个答案是正确的。
    • @Chris:我不想卷入一场关于演员表风格的圣战,但在这种情况下使用 C 风格演员表在语义上是完全正确的。
    • @AdamRosenfield 将副词链接在一起在语义上也是完全正确的,但这并不能使它成为好的风格! xD
    【解决方案5】:

    上述答案很好,但在我的情况下,将函数转换为静态的第一种方法不起作用。我试图将现有代码转换为线程函数,但该代码已经有很多对非静态类成员的引用。封装成 C++ 对象的第二种解决方案有效,但有 3 级包装器来运行线程。

    我有一个替代解决方案,它使用现有的 C++ 构造 - 'friend' 函数,它非常适合我的情况。 我如何使用“朋友”的示例(将使用上面相同的示例来显示如何使用朋友将其转换为紧凑形式)

        class MyThreadClass
        {
        public:
           MyThreadClass() {/* empty */}
           virtual ~MyThreadClass() {/* empty */}
    
           bool Init()
           {
              return (pthread_create(&_thread, NULL, &ThreadEntryFunc, this) == 0);
           }
    
           /** Will not return until the internal thread has exited. */
           void WaitForThreadToExit()
           {
              (void) pthread_join(_thread, NULL);
           }
    
        private:
           //our friend function that runs the thread task
           friend void* ThreadEntryFunc(void *);
    
           pthread_t _thread;
        };
    
        //friend is defined outside of class and without any qualifiers
        void* ThreadEntryFunc(void *obj_param) {
        MyThreadClass *thr  = ((MyThreadClass *)obj_param); 
    
        //access all the members using thr->
    
        return NULL;
        }
    

    当然,我们可以使用 boost::thread 并避免所有这些,但我试图修改 C++ 代码以不使用 boost(代码链接到 boost 只是为了这个目的)

    【讨论】:

      【解决方案6】:

      我的第一个答案是希望它对某人有用: 我现在这是一个老问题,但我遇到了与上述问题完全相同的错误,因为我正在编写一个 TcpServer 类并且我试图使用 pthreads。我发现了这个问题,现在我明白为什么会这样了。我最终这样做了:

      #include <thread>
      

      线程运行方法 -> void* TcpServer::sockethandler(void* lp) {/*code here*/}

      我用 lambda 调用它 -> std::thread( [=] { sockethandler((void*)csock); } ).detach();

      这对我来说似乎是一种干净的方法。

      【讨论】:

        【解决方案7】:

        C++ : How to pass class member function to pthread_create()?

        http://thispointer.com/c-how-to-pass-class-member-function-to-pthread_create/

        typedef void * (*THREADFUNCPTR)(void *);
        
        class C { 
           // ...
           void *print(void *) { cout << "Hello"; }
        }
        
        pthread_create(&threadId, NULL, (THREADFUNCPTR) &C::print, NULL);
        

        【讨论】:

          【解决方案8】:

          在我看来,太多次我找到了解决您所要求的问题的方法,这太复杂了。 例如,您必须定义新的类类型、链接库等。 所以我决定写几行代码让最终用户 基本上能够“线程化”任何类的“void ::method(void)”。 为了确保我实施的这个解决方案可以扩展、改进等,所以, 如果您需要更具体的方法或功能,请添加它们,并请善待我。

          这里有 3 个文件展示了我所做的事情。

              // A basic mutex class, I called this file Mutex.h
          #ifndef MUTEXCONDITION_H_
          #define MUTEXCONDITION_H_
          
          #include <pthread.h>
          #include <stdio.h>
          
          class MutexCondition
          {
          private:
              bool init() {
                  //printf("MutexCondition::init called\n");
                  pthread_mutex_init(&m_mut, NULL);
                  pthread_cond_init(&m_con, NULL);
                  return true;
              }
          
              bool destroy() {
                  pthread_mutex_destroy(&m_mut);
                  pthread_cond_destroy(&m_con);
                  return true;
              }
          
          public:
              pthread_mutex_t m_mut;
              pthread_cond_t m_con;
          
              MutexCondition() {
                  init();
              }
              virtual ~MutexCondition() {
                  destroy();
              }
          
              bool lock() {
                  pthread_mutex_lock(&m_mut);
                  return true;
              }
          
              bool unlock() {
                  pthread_mutex_unlock(&m_mut);
                  return true;
              }
          
              bool wait() {
                  lock();
                  pthread_cond_wait(&m_con, &m_mut);
                  unlock();
                  return true;
              }
          
              bool signal() {
                  pthread_cond_signal(&m_con);
                  return true;
              }
          };
          #endif
          // End of Mutex.h
          

          // 封装所有线程化方法工作的类(test.h):

          #ifndef __THREAD_HANDLER___
          #define __THREAD_HANDLER___
          
          #include <pthread.h>
          #include <vector>
          #include <iostream>
          #include "Mutex.h"
          
          using namespace std;
          
          template <class T> 
          class CThreadInfo
          {
            public:
              typedef void (T::*MHT_PTR) (void);
              vector<MHT_PTR> _threaded_methods;
              vector<bool> _status_flags;
              T *_data;
              MutexCondition _mutex;
              int _idx;
              bool _status;
          
              CThreadInfo(T* p1):_data(p1), _idx(0) {}
              void setThreadedMethods(vector<MHT_PTR> & pThreadedMethods)
              {
                  _threaded_methods = pThreadedMethods;
                _status_flags.resize(_threaded_methods.size(), false);
              }
          };
          
          template <class T> 
          class CSThread {
            protected:
              typedef void (T::*MHT_PTR) (void);
              vector<MHT_PTR> _threaded_methods;
              vector<string> _thread_labels;
              MHT_PTR _stop_f_pt;
              vector<T*> _elements;
              vector<T*> _performDelete;
              vector<CThreadInfo<T>*> _threadlds;
              vector<pthread_t*> _threads;
              int _totalRunningThreads;
          
              static void * gencker_(void * pArg)
              {
                CThreadInfo<T>* vArg = (CThreadInfo<T> *) pArg;
                vArg->_mutex.lock();
                int vIndex = vArg->_idx++;
                vArg->_mutex.unlock();
          
                vArg->_status_flags[vIndex]=true;
          
                MHT_PTR mhtCalledOne = vArg->_threaded_methods[vIndex];
                (vArg->_data->*mhtCalledOne)();
                vArg->_status_flags[vIndex]=false;
                  return NULL;
              }
          
            public:
              CSThread ():_stop_f_pt(NULL), _totalRunningThreads(0)  {}
              ~CSThread()
              {
                for (int i=_threads.size() -1; i >= 0; --i)
                    pthread_detach(*_threads[i]);
          
                for (int i=_threadlds.size() -1; i >= 0; --i)
                  delete _threadlds[i];
          
                for (int i=_elements.size() -1; i >= 0; --i)
                   if (find (_performDelete.begin(), _performDelete.end(), _elements[i]) != _performDelete.end())
                        delete _elements[i];
              }
              int  runningThreadsCount(void) {return _totalRunningThreads;}
              int  elementsCount()        {return _elements.size();}
              void addThread (MHT_PTR p, string pLabel="") { _threaded_methods.push_back(p); _thread_labels.push_back(pLabel);}
              void clearThreadedMethods() { _threaded_methods.clear(); }
              void getThreadedMethodsCount() { return _threaded_methods.size(); }
              void addStopMethod(MHT_PTR p)  { _stop_f_pt  = p; }
              string getStatusStr(unsigned int _elementIndex, unsigned int pMethodIndex)
              {
                char ch[99];
          
                if (getStatus(_elementIndex, pMethodIndex) == true)
                  sprintf (ch, "[%s] - TRUE\n", _thread_labels[pMethodIndex].c_str());
                else 
                  sprintf (ch, "[%s] - FALSE\n", _thread_labels[pMethodIndex].c_str());
          
                return ch;
              }
              bool getStatus(unsigned int _elementIndex, unsigned int pMethodIndex)
              {
                if (_elementIndex > _elements.size()) return false;
                return _threadlds[_elementIndex]->_status_flags[pMethodIndex];
              }
          
              bool run(unsigned int pIdx) 
              {
                T * myElem = _elements[pIdx];
                _threadlds.push_back(new CThreadInfo<T>(myElem));
                _threadlds[_threadlds.size()-1]->setThreadedMethods(_threaded_methods);
          
                int vStart = _threads.size();
                for (int hhh=0; hhh<_threaded_methods.size(); ++hhh)
                    _threads.push_back(new pthread_t);
          
                for (int currentCount =0; currentCount < _threaded_methods.size(); ++vStart, ++currentCount)
                {
                          if (pthread_create(_threads[vStart], NULL, gencker_, (void*) _threadlds[_threadlds.size()-1]) != 0)
                  {
                          // cout <<"\t\tThread " << currentCount << " creation FAILED for element: " << pIdx << endl;
                              return false;
                          }
                  else
                  {
                      ++_totalRunningThreads;
                       // cout <<"\t\tThread " << currentCount << " creation SUCCEDED for element: " << pIdx << endl;
                          }
                }
                return true;
              }
          
              bool run() 
              {
                      for (int vI = 0; vI < _elements.size(); ++vI) 
                      if (run(vI) == false) return false;
                    // cout <<"Number of currently running threads: " << _totalRunningThreads << endl;
                  return true;
              }
          
              T * addElement(void)
              {
                int vId=-1;
                return addElement(vId);
              }
          
              T * addElement(int & pIdx)
              {
                T * myElem = new T();
                _elements.push_back(myElem);
                pIdx = _elements.size()-1;
                _performDelete.push_back(myElem);
                return _elements[pIdx];
              }
          
              T * addElement(T *pElem)
              {
                int vId=-1;
                return addElement(pElem, vId);
              }
          
              T * addElement(T *pElem, int & pIdx)
              {
                _elements.push_back(pElem);
                pIdx = _elements.size()-1;
                return pElem;
              }
          
              T * getElement(int pId) { return _elements[pId]; }
          
              void stopThread(int i)  
              {
                if (_stop_f_pt != NULL) 
                {
                   ( _elements[i]->*_stop_f_pt)() ;
                }
                pthread_detach(*_threads[i]);
                --_totalRunningThreads;
              }
          
              void stopAll()  
              {
                if (_stop_f_pt != NULL) 
                  for (int i=0; i<_elements.size(); ++i) 
                  {
                    ( _elements[i]->*_stop_f_pt)() ;
                  }
                _totalRunningThreads=0;
              }
          };
          #endif
          // end of test.h
          

          // 我在 linux 上编译的使用示例文件“test.cc” 封装所有线程化方法的工作的类: g++ -o mytest.exe test.cc -I。 -lpthread -lstdc++

          #include <test.h>
          #include <vector>
          #include <iostream>
          #include <Mutex.h>
          
          using namespace std;
          
          // Just a class for which I need to "thread-ize" a some methods
          // Given that with OOP the objecs include both "functions" (methods)
          // and data (attributes), then there is no need to use function arguments,
          // just a "void xxx (void)" method.
          // 
          class TPuck
          {
            public:
             bool _go;
             TPuck(int pVal):_go(true)
             {
               Value = pVal;
             }
             TPuck():_go(true)
             {
             }
             int Value;
             int vc;
          
             void setValue(int p){Value = p; }
          
             void super()
             {
               while (_go)
               {
                cout <<"super " << vc << endl;
                      sleep(2);
                   }
                cout <<"end of super " << vc << endl;
             }
          
             void vusss()
             {
               while (_go)
               {
                cout <<"vusss " << vc << endl;
                sleep(2);
               }
                cout <<"end of vusss " << vc << endl;
             }
          
             void fazz()
             {
               static int vcount =0;
               vc = vcount++;
               cout <<"Puck create instance: " << vc << endl;
               while (_go)
               {
                 cout <<"fazz " << vc << endl;
                 sleep(2);
               }
               cout <<"Completed TPuck..fazz instance "<<  vc << endl;
             }
          
             void stop()
             {
                _go=false;
                cout << endl << "Stopping TPuck...." << vc << endl;
             }
          };
          
          
          int main(int argc, char* argv[])
          {
            // just a number of instances of the class I need to make threads
            int vN = 3;
          
            // This object will be your threads maker.
            // Just declare an instance for each class
            // you need to create method threads
            //
            CSThread<TPuck> PuckThreadMaker;
            //
            // Hera I'm telling which methods should be threaded
            PuckThreadMaker.addThread(&TPuck::fazz, "fazz1");
            PuckThreadMaker.addThread(&TPuck::fazz, "fazz2");
            PuckThreadMaker.addThread(&TPuck::fazz, "fazz3");
            PuckThreadMaker.addThread(&TPuck::vusss, "vusss");
            PuckThreadMaker.addThread(&TPuck::super, "super");
          
            PuckThreadMaker.addStopMethod(&TPuck::stop);
          
            for (int ii=0; ii<vN; ++ii)
            {
              // Creating instances of the class that I need to run threads.
              // If you already have your instances, then just pass them as a
              // parameter such "mythreadmaker.addElement(&myinstance);"
              TPuck * vOne = PuckThreadMaker.addElement();
            }
          
            if (PuckThreadMaker.run() == true)
            {
              cout <<"All running!" << endl;
            }
            else
            {
              cout <<"Error: not all threads running!" << endl;
            }
          
            sleep(1);
            cout <<"Totale threads creati: " << PuckThreadMaker.runningThreadsCount()  << endl;
            for (unsigned int ii=0; ii<vN; ++ii)
            {
              unsigned int kk=0;
              cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
              cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
              cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
              cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
              cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
            }
          
            sleep(2);
            PuckThreadMaker.stopAll();
            cout <<"\n\nAfter the stop!!!!" << endl;
            sleep(2);
          
            for (int ii=0; ii<vN; ++ii)
            {
              int kk=0;
              cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
              cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
              cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
              cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
              cout <<"status for element " << ii << " is " << PuckThreadMaker.getStatusStr(ii, kk++) << endl; 
            }
          
            sleep(5);
            return 0;
          }
          
          // End of test.cc
          

          【讨论】:

            【解决方案9】:

            这是一个有点老的问题,但却是许多人面临的一个非常普遍的问题。 以下是使用 std::thread 处理此问题的一种简单而优雅的方法

            #include <iostream>
            #include <utility>
            #include <thread>
            #include <chrono>
            
            class foo
            {
                public:
                    void bar(int j)
                    {
                        n = j;
                        for (int i = 0; i < 5; ++i) {
                            std::cout << "Child thread executing\n";
                            ++n;
                            std::this_thread::sleep_for(std::chrono::milliseconds(10));
                        }
                    }
                    int n = 0;
            };
            
            int main()
            {
                int n = 5;
                foo f;
                std::thread class_thread(&foo::bar, &f, n); // t5 runs foo::bar() on object f
                std::this_thread::sleep_for(std::chrono::milliseconds(20));
                std::cout << "Main Thread running as usual";
                class_thread.join();
                std::cout << "Final value of foo::n is " << f.n << '\n';
            }
            

            上面的代码还负责将参数传递给线程函数。

            请参阅std::thread 文档了解更多详情。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-01-15
              相关资源
              最近更新 更多