2015-12-23 28 views
1

這個線程啓動了here但是由於缺乏一個很好的例子(爲了避免刪除所有的問題)寫在這裏。C++,pthread和靜態回調。 「this」返回一個指向基類的指針而不是派生的指針(第2部分)

因此,在下面的示例中,void cppthread::ThreadedFunc()被衍生爲獨立線程執行。相反,我更願意執行void ThreadedWrite::ThreadedFunc()。我怎樣才能做到這一點? (代碼後一些更多的細節如下)

cppthread.hpp

#ifndef CPPTHREAD_HPP 
#define CPPTHREAD_HPP 

#include <pthread.h> 

using namespace std; 

class cppthread 
{ 
    public: 
     cppthread(); 
     virtual ~cppthread(); 

     virtual void threadedFunc(); 
     ///parentObj (ie "this" pte from caller") is 
     ///necessary in order to execute the correct 
     ///threadedFunc() even when the derived class 
     ///wants to spawn a thread. 
     int spawn(void *parentObj = NULL); 
     void terminate(); 

    protected: 
     pthread_mutex_t mtx; 
     bool exitThread; 

    private: 
     /* add your private declarations */ 
     int join(); 

     pthread_t threadId; 
}; 

#endif /* CPPTHREAD_HPP */ 

cppthread.cpp

#include <stdio.h> 
#include <errno.h> 
#include <stdlib.h> 

#include "cppthread.hpp" 

void* threadCallback(void* obj); 

cppthread::cppthread() 
{ 
    exitThread = false; 
    pthread_mutex_init(&mtx, NULL); 

} 


cppthread::~cppthread() 
{ 
    if (!exitThread) 
     terminate(); 
    pthread_mutex_destroy(&mtx); 
} 

void cppthread::threadedFunc() 
{ 
    while (!exitThread) 
    { 
     printf("Hello from cppthread::threadfunc. This should not be run once derived and redefined.\n"); 
    } 
    if (exitThread) 
    { 
     printf("graceful exit from cppthread::threadfunc. This should not be run once derived and redefined.\n"); 
    } 
    pthread_exit((void*)0); 
} 

int cppthread::spawn(void* parentObj) 
{ 
    int ret; 
    printf("parentObj = %p\n", parentObj); 
    if (parentObj == NULL) 
    { 
     ret = pthread_create(&threadId, 0, &threadCallback, this); 
     printf("cppthread_create with \"this\" \n"); 
    } 
    else 
    { 
     ret = pthread_create(&threadId, 0, &threadCallback, parentObj); 
     printf("cppthread_create with parentObj\n"); 
    } 

    if (ret != 0) 
    { 
     printf("cppthread_create error\n"); 
     exit(EXIT_FAILURE); 
    } 
    else 
    { 
     //printf("cppthread::threadID= %lu\n",threadId); 
    } 
    return ret; 
} 

void cppthread::terminate() 
{ 
    exitThread = true; 
    join(); 
} 

int cppthread::join() 
{ 
    int status , ret; 
    //printf("cppthread::join_threadID= %lu\n",threadId); 
    ret = pthread_join(threadId,(void**)&status); 
    if (ret != 0) 
    { 
     printf("cppthread_join error: "); 
     switch (ret) 
     { 
      case EDEADLK: printf("deadlock\n"); break; 
      case EINVAL: printf("thread not joinable\n"); break; 
      case ESRCH: printf("threadID not found\n"); break; 
      default : printf("unknown error\n"); break; 
     } 
    } 
    return status; 
} 

//---------------------------------------------------------------------- 
void* threadCallback(void* obj) 
{ 
    static_cast<cppthread*>(obj)->threadedFunc(); 
    return(0); 
} // callback 

threadedwrite.hpp

#ifndef THREADEDWRITE_HPP 
#define THREADEDWRITE_HPP 

#include "cppthread.hpp" 

using namespace std; 

class ThreadedWrite : public cppthread 
{ 
    public: 
     ThreadedWrite(ThreadedWrite* mySelf); 
     virtual ~ThreadedWrite(); 

     void threadedFunc(); 
     void rrdupdate_thread(); 

     ///inherited significant members: from cppthread 
     /// int spawn(); 
     /// void terminate(); 
     ///protected 
     /// pthread_mutex_t mtx; 
     /// bool exitThread; 

    private: 
     ThreadedWrite* instancePtr; 
}; 

#endif /* THREADEDWRITE_HPP */ 

threadedwrite.cpp

#include <iostream> 
#include "threadedwrite.hpp" 


ThreadedWrite::ThreadedWrite(ThreadedWrite* mySelf):instancePtr(mySelf) 
{ 
    cout << "instancePtr = " << instancePtr << endl; 
} 

ThreadedWrite::~ThreadedWrite() 
{ 

} 

void ThreadedWrite::threadedFunc() 
{ 
    if (!exitThread) 
    { 
     cout << "this is the ThreadedWrite::threadedFunc() running!" << endl; 
    } 
    else 
    { 
     cout << "ThreadedWrite::threadedFunc must exist now" << endl; 
    } 

    pthread_exit((void*)0); 
} 

void ThreadedWrite::rrdupdate_thread() 
{ 
    cout << "about to spawn" << endl; 
    spawn(instancePtr); 
} 

的main.cpp

#include <iostream> 

#include "threadedwrite.hpp" 

using namespace std; 

//-------main body------------------------------------------------------ 
int main(int argc, char* argv[]) 
{ 
    ThreadedWrite thrrdupd(&thrrdupd); 
    cout << "hello from main 1 " << &thrrdupd << endl; 
    thrrdupd.rrdupdate_thread(); 
    cout << "hello from main 2 " << &thrrdupd << endl; 
    return 0; 
} 

上面產生的輸出(我):

instancePtr = 0x7fff39d17860 
hello from main 1 0x7fff39d17860 
about to spawn 
parentObj = 0x7fff39d17860 
cppthread_create with parentObj 
hello from main 2 0x7fff39d17860 
graceful exit from cppthread::threadfunc. This should not be run once derived and redefined. 

所以執行從派生類 「ThreadedWrite」 內上述cppthread::spawn()呼叫,實際上提供了一個「這「指向callback()函數指向cppthread::ThreadedFunc(),而不是ThreadedWrite::ThreadedFunc()

你也可以看到我試過(通過「instancePtr」基礎結構)將指向「ThreadedWrite」實例的指針傳遞迴回調函數。但是這也失敗了。

此外,最好我想保持cppthread類儘可能通用,以便能夠在多種情況下使用它。

你要知道,如果我從threadedwrite.cpp從main.cpp中刪除「重生(instancePtr)」,並調用產卵這樣

int main(int argc, char* argv[]) 
{ 
     ThreadedWrite thrrdupd(&thrrdupd); 
     cout << "hello from main 1 " << &thrrdupd << endl; 
     thrrdupd.rrdupdate_thread(); 
     thrrdupd.spawn(); 
     cout << "hello from main 2 " << &thrrdupd << endl; 
     return 0; 
} 

,我得到的是預期的輸出(並希望)之一,它看起來像這樣:

instancePtr = 0x7ffd24b04ed0 
hello from main 1 0x7ffd24b04ed0 
about to spawn 
parentObj = (nil) 
cppthread_create with "this" 
hello from main 2 0x7ffd24b04ed0 
this is the ThreadedWrite::threadedFunc() running! 
+0

你爲什麼要存儲'instancePtr'而不是僅僅使用'this'? –

+0

@AlanStokes當callback()函數中的「this」指針指向基而不是派生對象時。所以我試圖驗證我是否想要正確傳遞。我同意它現在是冗餘代碼。 – nass

+0

所以沒有主要的加入操作 – StoryTeller

回答

5

你需要等待線程從main返回之前終止,因爲這會破壞你的對象。

否則,你有一個競爭條件:

  1. 線程啓動。
  2. thrrdupd在您離開main時開始遭到毀壞。
  3. ~ThreadedWrite運行;此時該對象不再是ThreadedWrite,而是cppthread
  4. ~cppthread運行並等待該線程。
  5. 線程調用回調函數,並且因爲對象現在具有動態類型cppthread,因此調用了cppthread::threadedFunc

5.可能發生在3.之前,在這種情況下,您將得到預期的輸出。

如果你確定你等待線程在第3步完成,那麼它會正常工作。也許你可以在~ThreadedWrite內撥打terminate

+0

我真的認爲派生類充當統一塊類(基礎+派生)。我不知道派生的東西可能會在基礎仍然存在的時候死掉......我認爲'〜ThreadWrite()'也調用了'〜cppthread()'。這是今天學到的新東西。 – nass

+0

@nass你不明白這個問題。這兩個析構函數都被稱爲確實,但這不會立即發生,有競爭條件 - 而'〜ThreadWrite()'工作時,您稱爲虛擬函數。 – Slava

+0

感謝Alan對這個很好的解釋。 –

相關問題