2012-08-08 55 views
4

我有點困惑如何將對象傳遞給pthread_create函數。我發現很多零散的信息關於轉換爲void *,將參數傳遞給pthread_create等,但沒有任何關聯它們。我只是想確保我將它們聯繫在一起,並沒有做任何愚蠢的事情。假設我有以下線程類: 編輯:固定錯誤匹配static_cast鑄造到void *將對象傳遞給pthread在c + +

class ProducerThread { 
    pthread_t thread; 
    pthread_attr_t thread_attr; 
    ProducerThread(const ProducerThread& x); 
    ProducerThread& operator= (const ProducerThread& x); 
    virtual void *thread_routine(void *arg) { 
     ProtectedBuffer<int> *buffer = static_cast<ProtectedBuffer<int> *> arg; 
     int randomdata; 

     while(1) { 
      randomdata = RandomDataGen(); 
      buffer->push_back(randomdata); 
     } 

     pthread_exit(); 
    } 
public: 
    ProtectedBuffer<int> buffer; 

    ProducerThread() { 
     int err_chk; 

     pthread_attr_init(&thread_attr); 
     pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED); 

     err_chk = pthread_create(&thread, &thread_attr, thread_routine, static_cast<void *> arg); 
     if (err_chk != 0) { 
      throw ThreadException(err_chk); 
     } 
    } 
    ~ProducerThread() { 
     pthread_cancel(&thread); 
     pthread_attr_destroy(&thread_attr); 
    } 
} 

爲了澄清,在ProtectedBuffer類中的數據只能用像ProtectedBuffer::push_back(int arg)方法,它使用互斥來保護實際的數據訪問。

我的主要問題是:我正確使用static_cast嗎?而我的第二個問題是我需要在virtual void *thread_routine(void *arg)第一行,我複製傳遞的空指針指向ProtectedBuffer?另外,如果我做了其他任何可能導致問題的東西,我會很高興聽到它。

+5

呃,你不能將成員函數傳給pthread_create,可以嗎? (無關:爲什麼有人需要C++中的線程基類?C++中的多態基類應該具有虛擬析構函數) – 2012-08-08 19:01:13

+1

@ R.MartinhoFernandes:不,它應該是靜態的。 (線程類的'this'可以作爲線程例程的參數,爲線程例程提供狀態。同意。) – jxh 2012-08-08 19:01:54

+0

看看這個:http://stackoverflow.com/questions/8920441/the-fouth-parameter-in -pthread-create-function – PiotrNycz 2012-08-08 19:10:23

回答

3

如果你想要走這條路,我相信你想是這樣的:

編輯:基於詹姆斯甘孜的回答,添加一個單獨的activate法施工完成後,啓動線程。

class GenericThread { 
protected: 
    GenericThread() { 
     //... 
    } 
    virtual ~GenericThread() {} 

    int activate() { 
     return pthread_create(..., GenericThreadEntry, this); 
    } 

    virtual void * thread_routine() = 0; 

    #if 0 
    // This code is wrong, because the C routine callback will do so using the 
    // C ABI, but there is no guarantee that the C++ ABI for static class methods 
    // is the same as the C ABI. 
    static void * thread_entry (void *arg) { 
     GenericThread *t = static_cast<GenericThread *>(arg); 
     return t->thread_routine(); 
    } 
    #endif 
}; 

extern "C" void * GenericThreadEntry (void *) { 
    GenericThread *t = static_cast<GenericThread *>(arg); 
    return t->thread_routine(); 
} 

然後,ProducerThread將從GenericThread派生。

編輯:在C++標準搜索extern "C"。沒有要求函數指針必須指向C庫函數可以調用C函數的函數。由於指針正在被傳遞,所以鏈接需求不適用,因爲鏈接用於解析名稱。根據C++ 2011草案(n3242)的規定,指向靜態方法的指針是一個函數指針。 3.9.2p3:

除指向靜態成員的指針外,指向指針的文本不適用於指向成員的指針。

編輯:認錯。 C庫將調用假設C應用程序二進制接口的回調函數。使用C++連接的函數可能使用與C ABI不同的ABI。這就是爲什麼在傳遞給C庫的回調函數時需要使用與extern "C"鏈接的函數。我對James Kanze懷疑他表示誠摯的歉意,並衷心感謝Loki Astari對我的偏見。

+0

請在downvoting時留下評論,所以我知道如何改進答案。謝謝! – jxh 2012-08-08 20:08:40

+3

downvoting沒有評論是如此普遍:http://meta.stackexchange.com/a/22935/138817這樣的要求是浪費時間。如果投票的人想要發表評論,那麼他們已經這樣做了。 – 2012-08-08 21:05:57

+0

@LokiAstari:我現在明白了,謝謝你的解釋。 – jxh 2012-08-08 21:50:26

4

您的代碼有許多問題。對於初學者,我並不是 看到你正在鑄造的arg是在宣佈的,所以我不能說 的情況是否合適。

也許更重要的是,thread_routine是一個成員函數,所以它不能轉換爲指向函數的指針。該函數傳遞給 pthread_create必須是extern "C",所以它不能成爲一個成員,句號; 它必須是一個免費函數聲明extern "C"。如果你想要把一個 成員函數,傳遞一個指向對象作爲最後一個參數,並 取消對它的引用在extern "C"功能:

extern "C" void* startProducerThread(void* arg) 
{ 
    return static_cast<ProducerThread*>(arg)->thread_routine(); 
} 

並啓動線程:

int status = pthread_create(&thread, &thread_attr, startProducerThread, this); 

只是不要在構造函數中這樣做。另一個線程可能在對象完全構建之前運行 ,具有災難性 影響。

而且,非常肯定的說在startProducerThread投是 準確同類型傳遞到pthread_create指針。如果 您投到startProducerThread中的基類,那麼非常非常非常非常非常非常 確定它是指向該基類的指針,您傳遞給 pthread_create;如果需要,使用明確的演員表(在 startProducerThread,而不是void*的類型)。

最後,而不是你的實際問題有關:如果 ProtectedBuffer有這樣的std::vector接口,並 返回內部數據的引用,沒有辦法,你可以把它 線程安全的。保護需要在課堂上進行。

+0

關於在構造函數中激活的好處,我會解決我的答案。 – jxh 2012-08-08 19:19:41

+0

'ProtectedBuffer'實際上在內部使用一個deque容器。這是我問過的前一個問題的主題(http://stackoverflow.com/questions/11640681/thread-safe-way-to-build-mutex-protection-into-a-c-class)。我如何確保成員函數返回'ProtectedBuffer'中的數據副本而不是引用? – Beezum 2012-08-08 19:44:59

+0

http://stackoverflow.com/a/11742708/14065 – 2012-08-08 21:20:17