2012-05-05 65 views
3

我想給每個線程一些線程特定的數據;這可以使用線程參數來完成嗎?POSIX線程本地數據C

所以當創建線程時,我傳遞一個變量,並且在線程函數中,我更改它的值並將其用作每個線程的特定數據?

int main(void){ 
    ... 
    int Tparam = 0; 
    ... 
    rc = pthread_create(&threads[c1], NULL, Thread_Pool, (void *)Tparam); 
    ... 
} 

然後在Thread_Pool功能我用它像這樣

void *Thread_Pool(void *param){ 
    int id; 
    id = (int) param; 
    id = value; // can this value be a specific value for this thread? 
} 
+0

pthread_keycreate等閱讀文檔。 – bmargulies

+3

爲什麼不使用線程局部變量,使用__thread前綴?如__thread int tl_var;其次,你不能寫空指針,因爲它指向寫保護的位置0!如果你嘗試這樣做,你會得到一個分段錯誤。 – MetallicPriest

+0

@bmargulies我讀了pthread_keycreate,我只是想知道這是否會起作用,因爲我認爲它更容易,並且比你的答案要好。 – CodeRed

回答

4

如果您顯示Tparam的聲明方式,可能會有所幫助。

但是,如果您希望每個線程都有自己的空間來存儲某些數據,那麼您可以安排將該空間作爲該函數的參數傳遞給線程。例如:

enum { NTHREADS = 10 }; 

struct TLS_Data 
{ 
    int id; 
    char buffer[2048]; 
    size_t index; 
} data[NTHREADS]; 

for (int c1 = 0; c < NTHREADS; c1++) 
{ 
    data[c1].index = c1; 
    data[c1].id = 0; 
    data[c1].buffer[0] = '\0'; 
    int rc = pthread_create(&threads[c1], NULL, Thread_Pool, &data[c1]); 
    ...handle errors, etc... 
} 

請注意缺少對pthread_create()的最後一個參數進行強制轉換;當範圍內有原型時,不需要將指針轉換爲void *

在您的Thread_Pool中,您似乎想將參數視爲整數;這也可以做到。傳遞一個指向整數的指針是乾淨的;你可以直接通過整數值,如果你真的堅持:

uintptr_t value = c1 + 10; 

rc = pthread_create(&threads[c1], NULL, Thread_Pool, (void *)value); 

由於value類型是uintptr_t,你知道它是能夠保持一個空指針,所以它給你的東西工作的最大機會。但是你正在與類型系統打交道,這使得編寫乾淨的代碼變得更加困難。

需要注意的一件事是,如果它們應該看到不同的值,則需要確保傳遞給線程函數(在您的示例中爲Thread_Pool())的數據不在線程之間共享。沒有線程的執行順序的保障,因此,如果你犯了一個錯誤,如:

uintptr_t value = c1 + 10; 

rc = pthread_create(&threads[c1], NULL, Thread_Pool, &value); 

(和代碼是在一個循環中),那麼會是沒有什麼每個線程功能保證會看到。要小心!

-2

我不明白你的問題;我仍然無法弄清楚你真的想做什麼。

在任何情況下,我會強烈建議你檢查網站:

他們短,但仍然含有大部分的東西,你應該很可能需要開始。

+0

我工作在一個多線程的網絡服務器,使用生產者消費者算法與信號量,我想給每個FD從緩衝區到特定的工作線程,所以它可以服務於該連接。 – CodeRed

1

你可以調用pthread_self()。它返回一個唯一的線程ID。請參閱juampa建議的LLNL URL上的API參考。

2

這個值可以是這個線程的特定值嗎?

嗯,第一件事第一,你可能希望這樣的:

int id = *((int*) param); 

即需要取消引用參數指針後一類給它一個指針。您無法取消引用無效指針,因爲void 沒有類型

現在 - 這裏發生了什麼?那麼,首先我們需要理解一些線程。首先 - 不存在distinction between a thread and a process in the kernel in Linux。絕對沒有。它們都是執行或任務的環境。但是,一個主要區別是線程化任務共享數據 - 除了線程堆棧之外。閱讀這個答案,你可以看到一個線程幾乎與其創建者共享其他內容。

但是,堆棧不能共享。堆棧跟蹤許多事情,例如程序在某些系統上的執行方式,返回值和函數參數。在函數內聲明的自動存儲持續時間變量 - 沒有任何其他修飾符的變量 - 也存儲在堆棧中。

這意味着 - 在你的線程函數中聲明的變量對該線程是唯一的。因此,考慮到你的函數:

void threadfunc(void* param) 
{ 
    int id = /* ??? */ 
} 

每個線程有自己的int id副本存儲在本地,將持續對螺紋的持續時間。你可以通過值傳遞給後續函數,或者指向它的指針。

因此,它是完全有效的調用:

int tParam[] = {1,2,3}; 

rc = pthread_create(&threads[1], NULL, Thread_Pool, (void *)&(tParam[1])); 
rc = pthread_create(&threads[2], NULL, Thread_Pool, (void *)&(tParam[2])); 
rc = pthread_create(&threads[3], NULL, Thread_Pool, (void *)&(tParam[3])); 

等。

+0

他不是取消引用指針。他傳遞一個僞裝成指針的整數,然後將該指針轉回到整數。這是POSIX線程中經常使用的概念,因爲如果線程在創建函數退出並且自動變量已被銷燬後啓動,那麼按地址傳遞自動整型變量可能會導致運行時錯誤(如果tParam可能會發生這種情況被分配在堆棧上)。 –

+0

@HristoIliev啊好的。那麼,他沒有包括一個聲明。這不是我要做的事情(在線程創建之前銷燬外部範圍),我不喜歡在指針類型中傳遞整型變量的想法 - 各種大小問題。讓我們假設人們假設指針類型是4字節,最近給我帶來了很多痛苦。在這種情況下,一個例子就是在32位系統上通過一個'void *'傳遞'uint64_t'。所以如果這是非常普遍的做法,那就不應該這樣。 – 2012-05-05 21:10:08