클래스의 pthread 함수 *){ cout <<

다음과 같은 수업이 있다고 가정 해 봅시다.

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(&t1, NULL, &c[0].print, NULL);

오류 출력 : 인수 ‘3’에 대해 ‘void * (tree_item ::) (void )’를 ‘void * ( ) (void )’ 로 변환 할 수 없습니다. ‘int pthread_create (pthread_t *, const pthread_attr_t *, void * ( ) (void ), 무효 *) ‘



답변

C ++ 클래스 멤버 함수에 숨겨진 this매개 변수가 전달 되었기 때문에 작성한 방식대로 수행 할 수 없습니다 . 사용할 pthread_create()값을 알지 못 this하므로 메소드를 함수로 캐스팅하여 컴파일러를 우회하려고합니다. 적절한 유형의 포인터를 사용하면 segmetnation 오류가 발생합니다. 정적 클래스 메서드 ( 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);


답변

스레드를 처리하는 가장 좋은 방법은 스레드를 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;
};

이를 사용하려면 스레드의 이벤트 루프를 포함하도록 구현 된 InternalThreadEntry () 메서드를 사용하여 MyThreadClass의 하위 클래스를 만듭니다. 물론 스레드 개체를 삭제하기 전에 스레드 개체에서 WaitForInternalThreadToExit ()를 호출해야합니다 (그리고 스레드가 실제로 종료되는지 확인하는 메커니즘이 있습니다. 그렇지 않으면 WaitForInternalThreadToExit ()가 반환되지 않음)


답변

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

    ...
}


답변

위의 답변은 좋지만 제 경우에는 함수를 정적으로 변환하는 첫 번째 접근 방식이 작동하지 않았습니다. 스레드 함수로 이동하기 위해 기존 코드를 변환하려고 시도했지만 해당 코드에는 이미 비 정적 클래스 멤버에 대한 참조가 많이 있습니다. C ++ 객체로 캡슐화하는 두 번째 솔루션은 작동하지만 스레드를 실행하기위한 3 단계 래퍼가 있습니다.

기존 C ++ 구조 인 ‘친구’기능을 사용하는 대체 솔루션이 있었고 제 경우에는 완벽하게 작동했습니다. 내가 ‘친구’를 사용한 방법의 예 (친구를 사용하여 압축 형식으로 변환하는 방법을 보여주는 이름에 위의 동일한 예를 사용합니다)

    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를 사용할 수 있고 이러한 모든 것을 피할 수 있지만, 저는 boost를 사용하지 않도록 C ++ 코드를 수정하려고했습니다 (코드는 단지이 목적을 위해 boost에 대해 링크되었습니다)


답변

누군가에게 유용 할 것이라는 희망의 첫 번째 대답 : 이제 이것은 오래된 질문이지만 TcpServer 클래스를 작성하고 pthread를 사용하려고 할 때 위의 질문과 똑같은 오류가 발생했습니다. 나는이 질문을 발견했고 그것이 왜 일어 났는지 이제 이해합니다. 나는 이것을 끝내었다.

#include <thread>

스레드 실행 방법-> void* TcpServer::sockethandler(void* lp) {/*code here*/}

그리고 나는 그것을 람다로 부른다-> std::thread( [=] { sockethandler((void*)csock); } ).detach();

그것은 나에게 깨끗한 접근 방식으로 보입니다.


답변

나는 당신이 요구하는 것을 해결하는 방법을 너무 많이 찾았습니다. 제 생각에는 너무 복잡합니다. 예를 들어 새로운 클래스 유형, 링크 라이브러리 등을 정의해야합니다. 그래서 최종 사용자가 기본적으로 “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


답변

이것은 약간 오래된 질문이지만 많은 사람들이 직면하는 매우 일반적인 문제입니다. 다음은 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 문서를 참조하십시오.