2012-05-05 30 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