λ€μκ³Ό κ°μ μμ μ΄ μλ€κ³ κ°μ ν΄ λ΄ μλ€.
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 λ¬Έμλ₯Ό μ°Έμ‘°νμμμ€.