2010-09-17 125 views
2

這是我用多線程處理的問題。 proc需要是靜態的,這意味着我看到2個線程可以通信和共享數據的唯一途徑是通過全局範圍。這看起來不太乾淨,也不覺得很OO。我知道我可以在一個類中創建一個靜態proc函數,但這仍然是靜態的。例如,我想在某個類中使用線程特效,例如:我可以創建一個MD5校驗和類,並擁有這些對象的數組,每個對象都在它們自己的線程中檢查其哈希,而UI線程不會因此而受到影響,另一個類可能會簡單地跟蹤句柄並在說出「完成」之前等待多個對象。這個限制通常如何克服?多線程和類?

+0

你可以在你的陳述上更準確,然後在你的問題上?這太模糊了,我很難弄清楚你正在做什麼線程化的假設(根據操作系統的不同,這些線程有幾種不同的風格),甚至更少你真正想知道的。爲什麼這是一個C問題? – 2010-09-17 19:11:26

+0

許多進程間通信(IPC)工具也可以在線程之間使用。管道,插座,文件。每個都帶有成本和收益。時間做一些閱讀...... – dmckee 2010-09-17 19:12:35

+0

我已經拿走了C標記,因爲在答案中的混淆顯示,在這個問題中'靜態'只是靜態'成員函數在C++意義上而不是'靜態'符號混淆了所有尋找C的人。 – 2010-09-17 19:44:10

回答

3

如果你想在那裏啓動一個線程,你不能避免使用靜態函數。但是,您可以(使用Windows)將此指針作爲參數傳遞,並在另一端使用它來輸入類實例。

#include <windows.h> 

class Threaded { 
    static DWORD WINAPI StaticThreadEntry(LPVOID me) { 
     reinterpret_cast<Threaded*>(me)->ThreadEntry(); 
     return 0; 
    } 

    void ThreadEntry() { 
     // Stuff here. 
    } 

public: 
    void DoSomething() { 
     ::CreateThread(0, 0, StaticThreadEntry, this, 0, 0); 
    } 
}; 
+1

如果您使用Boost,您可以避免使用靜態函數(如果您使用C++編程,則應該這樣做) – jalf 2010-09-17 19:23:03

+0

靜態蹦牀絕對是您的選擇。使用pthread_create()的* nix解決方案是類似的。 – Boojum 2010-09-17 19:23:15

+1

@jalf有時候,Boost只是不可用,或者在不希望的項目中添加一個沉重的依賴項。 – 2010-09-17 19:45:23

3

在C++中,Boost.Thread很好地解決了這個問題。線程由仿函數表示,意味着(非靜態的)線程的入口點。

例如,一個線程可以這樣創建:

// define the thread functor 
struct MyThread { 
    MyThread(int& i) : i(i) {} 
    void operator()(){...} 
private: 
    int& i; 
}; 

// create the thread 
int j; 
boost::thread thr(MyThread(j)); 

通過將數據傳遞到線程仿函數的構造函數,我們可以傳遞參數給線程,而不必依賴於全局。 (在這種情況下,線程被給予對線程外聲明的整數j的引用。)

使用其他庫或API時,由(通常是靜態的)入口點跳轉到共享非靜態數據。

線程函數通常需要一個(有時是可選的)參數(通常爲void*),您可以使用該參數將實例數據傳遞給線程。

如果您使用此指針傳遞給某個對象的線程,那麼線程可以簡單地把指針回對象類型和訪問數據,而不必依賴於全局。

例如,(在僞代碼),這將有大致與上述升壓例相同的效果:

void MyThreadFunc(void* params) { 
    int& i = *(int*)params; 
    ... 
} 

int j; 
CreateThread(MyThreadFunc, &j); 

或者,參數可以是一個指針,指向一個對象,其(非靜態)成員函數你想打電話,讓你執行一個類成員函數而不是非成員。

+0

對我來說,這不是解決問題。這是一個完全相同的問題,因爲實例數據仍然通過void *傳入。有什麼好處?發生的只是你已經在層次結構中添加了另一個類。這是一個很好的可移植性解決方案,但它與問題無關。或者我錯過了一些讓你實例化線程並直接操作數據的東西? – 2010-09-17 19:19:23

+0

@San Jacinto:OP認爲唯一的解決方案是共享全球範圍內分配的數據。作爲參數傳遞給線程的'void *'不是全局的,所以它解決了OP的問題。更重要的是,Boost解決方案也保護了類型安全。 – jalf 2010-09-17 19:21:47

+0

是的,我看到你的意思後,再次閱讀帖子:) – 2010-09-17 19:26:50

0

線程創建程序通常允許您將參數傳遞到將在一個新的線程運行的功能。對於Posix pthread_create(...)和Win32 CreateThread(...)都是如此。這裏是一個使用Pthreads的例子:

void* func (void* arg) { 
    queue_t* pqueue = (queue_t*)arg; 

    // pull messages off the queue 
    val = queue_pull(pqueue); 

    return 0; 
} 

int main (int argc, char* argv[]) { 
    pthread_t thread; 
    queue_t queue = queue_init(); 

    pthread_create(&thread, 0, func, &queue); 

    // push messages on the queue for the thread to process 
    queue_push(&queue, 123); 

    void* ignored; 
    pthread_join(&thread, &ignored); 

    return 0; 
} 

任何地方都沒有靜態。在C++程序中,你可以傳遞一個指向類的實例的指針。

+0

這是真的,但你是污染命名空間(在你的情況下,全局命名空間)。這就是爲什麼靜態成員函數是首選。通過使用一個,你有一個機制等於你所描述的沒有它創建的namspace問題。 – 2010-09-17 19:42:46

+0

如果你喜歡爲一切創建類,那很好。在C++中,如果這是你的包,你可以輕鬆地將線程函數包裝在命名空間中。按我的口味,它是六,六打。 – xscott 2010-09-17 21:13:06