Katakanlah saya memiliki kelas seperti
class c {
// ...
void *print(void *){ cout << "Hello"; }
}
Dan kemudian saya memiliki vektor c
vector<c> classes; pthread_t t1;
classes.push_back(c());
classes.push_back(c());
Sekarang, saya ingin membuat utas c.print();
Dan berikut ini adalah masalah saya di bawah ini: pthread_create(&t1, NULL, &c[0].print, NULL);
Kesalahan Ouput: tidak dapat mengubah 'void * (tree_item ::) (void )' menjadi 'void * ( ) (void )' untuk argumen '3' menjadi 'int pthread_create (pthread_t *, const pthread_attr_t *, void * ( ) (void ), kosong*)'
Cara favorit saya untuk menangani utas adalah merangkumnya di dalam objek C ++. Berikut contohnya:
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; };
Untuk menggunakannya, Anda cukup membuat subkelas MyThreadClass dengan metode InternalThreadEntry () yang diimplementasikan untuk memuat loop peristiwa thread Anda. Anda harus memanggil WaitForInternalThreadToExit () pada objek utas sebelum menghapus objek utas, tentu saja (dan memiliki beberapa mekanisme untuk memastikan utas benar-benar keluar, jika tidak WaitForInternalThreadToExit () tidak akan pernah kembali)
sumber
Anda harus memberikan
pthread_create
fungsi yang cocok dengan tanda tangan yang dicari. Apa yang Anda lewati tidak akan berhasil.Anda dapat menerapkan fungsi statis apa pun yang Anda suka untuk melakukan ini, dan fungsi tersebut dapat merujuk ke instance
c
dan menjalankan apa yang Anda inginkan di utas.pthread_create
dirancang untuk tidak hanya mengambil penunjuk fungsi, tetapi juga penunjuk ke "konteks". Dalam hal ini Anda hanya meneruskannya ke sebuah pointer ke sebuah instancec
.Misalnya:
static void* execute_print(void* ctx) { c* cptr = (c*)ctx; cptr->print(); return NULL; } void func() { ... pthread_create(&t1, NULL, execute_print, &c[0]); ... }
sumber
Jawaban di atas bagus, tetapi dalam kasus saya, pendekatan pertama yang mengubah fungsi menjadi statis tidak berfungsi. Saya mencoba mengubah kode yang keluar untuk pindah ke fungsi utas tetapi kode itu sudah banyak referensi ke anggota kelas non-statis. Solusi kedua untuk mengenkapsulasi ke dalam objek C ++ berfungsi, tetapi memiliki pembungkus 3 tingkat untuk menjalankan utas.
Saya memiliki solusi alternatif yang menggunakan konstruksi C ++ yang ada - fungsi 'teman', dan itu berfungsi sempurna untuk kasus saya. Contoh bagaimana saya menggunakan 'teman' (akan menggunakan contoh yang sama di atas untuk nama yang menunjukkan bagaimana itu dapat diubah menjadi bentuk ringkas menggunakan teman)
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; }
Tentu saja, kita dapat menggunakan boost :: thread dan menghindari semua ini, tetapi saya mencoba mengubah kode C ++ agar tidak menggunakan boost (kode itu ditautkan ke boost hanya untuk tujuan ini)
sumber
Jawaban pertama saya dengan harapan akan berguna bagi seseorang: Saya sekarang ini adalah pertanyaan lama tetapi saya menemukan kesalahan yang persis sama dengan pertanyaan di atas saat saya menulis kelas TcpServer dan saya mencoba menggunakan pthreads. Saya menemukan pertanyaan ini dan sekarang saya mengerti mengapa itu terjadi. Saya akhirnya melakukan ini:
#include <thread>
metode untuk menjalankan threaded ->
void* TcpServer::sockethandler(void* lp) {/*code here*/}
dan saya menyebutnya dengan lambda ->
std::thread( [=] { sockethandler((void*)csock); } ).detach();
itu tampaknya pendekatan yang bersih bagi saya.
sumber
Terlalu sering saya menemukan cara untuk menyelesaikan apa yang Anda minta, menurut saya terlalu rumit. Misalnya Anda harus menentukan jenis kelas baru, pustaka tautan, dll. Jadi saya memutuskan untuk menulis beberapa baris kode yang memungkinkan pengguna akhir pada dasarnya dapat "thread-ize" a "void :: method (void)" dari kelas apapun. Yang pasti solusi yang saya terapkan ini dapat diperpanjang, ditingkatkan dll, jadi, jika Anda memerlukan metode atau fitur yang lebih spesifik, tambahkan mereka dan mohon berbaik hati agar saya tetap terhubung.
Berikut adalah 3 file yang menunjukkan apa yang saya lakukan.
// 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
// Kelas yang memasukkan semua pekerjaan ke thread-ize sebuah metode (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
// File contoh penggunaan "test.cc" yang di linux telah saya kompilasi dengan Kelas yang menyertakan semua pekerjaan untuk membuat utas metode: 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
sumber
Ini adalah pertanyaan yang agak lama tetapi masalah yang sangat umum yang dihadapi banyak orang. Berikut ini adalah cara sederhana dan elegan untuk menangani ini dengan menggunakan 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'; }
Kode di atas juga menangani pengiriman argumen ke fungsi utas.
Lihat dokumen std :: thread untuk lebih jelasnya.
sumber
Dugaan saya akan ini adalah b / c yang semakin rusak sedikit oleh C ++ b / c Anda mengirimkannya pointer C ++, bukan pointer fungsi C. Ternyata ada perbedaan . Coba lakukan
(void)(*p)(void) = ((void) *(void)) &c[0].print; //(check my syntax on that cast)
dan kemudian mengirim p.
Saya telah melakukan apa yang Anda lakukan dengan fungsi anggota juga, tetapi saya melakukannya di kelas yang menggunakannya, dan dengan fungsi statis - yang menurut saya membuat perbedaan.
sumber
C ++: Bagaimana cara mengirimkan fungsi anggota kelas ke 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);
sumber