我有一个功能:
void *findPos(void *param)
{
int origPos=(int)param;
...
}
我称之为线程转换器:
pthread_create( &threadIdArray[i], NULL, findPos, (void *)i );
现在,这样,我得到origPos的值作为类型化的void指针参数,即。一世。这感觉就像是一个肮脏的黑客,以解决被允许只传递无效指针到线程运行器功能的限制。
这可以用更干净的方式完成吗?
修改
请注意,我在pthread_create()
for循环中运行i
函数,因此传递指向i的指针可能不是一个安全的选择。
答案 0 :(得分:3)
当然:只提供指向int
的指针,这是API设计者的意图:
void *findPos(void *param)
{
int origPos=*(int *)param;
...
}
pthread_create( &threadIdArray[i], NULL, findPos, &i );
int
和void *
之间的转换是不安全的,因为转换不一定是可逆的。
当线程开始执行时,您还必须确保i
仍然有效(如果i
具有自动存储持续时间,例如,如果调用函数也调用pthread_join()
,则会出现这种情况。 )。
在你的情况下(i
是一个循环变量),你应该在一个安全的位置复制变量的值,例如在堆上通过malloc()
或者在具有适当的liefetime的堆栈上推送它:
static int args[THREAD_COUNT];
for(int i = 0; i < THREAD_COUNT; ++i)
{
args[i] = i;
pthread_create(&threadIdArray[i], NULL, findPos, args + i);
}
答案 1 :(得分:2)
好吧,你可以传递一个指向值的指针,或者将值包装在一个struct中并传递指针。后者本身并不是更清晰,但如果您需要在线程中使用多个int值的参数,则可扩展性更强。
<强>更新强>
我过去建议使用来自<stdint.h>
的使用intptr_t
来表示您打算将此整数转换为void *
,或者更加仔细地阅读文档(谢谢,Christoph) :
以下类型指定一个带符号的整数类型,其属性是任何有效的void指针都可以转换为此类型,然后转换回指向void的指针,结果将等于原始指针:intptr_t
这似乎表明,正如克里斯托夫所说,如果你走这条路,你就不安全了,所以不要
答案 2 :(得分:2)
您应该确保在您的系统上,参数的值在void-pointer内有足够的空间(请参阅数据类型intptr_t
)。使用“直接”方法传递double
值可能会出现问题。
我经常使用参数structur将值传递给线程(或其他)函数。
struct Param {
double foo;
int bar;
};
Param param;
param.foo = 1.0;
param.bar = 1;
pthread_create( &threadIdArray[i], NULL, findPos, ¶m );
答案 3 :(得分:1)
如果你想拥有可移植的代码,这是一个你不应该做的黑客攻击。首先,从void*
返回的转换未必如其他人所说的那样明确定义。
但不管怎样,这是一个肮脏的黑客攻击pthread_create
API的所有可能的意图。只需使用以下内容:
size_t * threadId = calloc(n, sizeof(size_t));
for (size_t i = 0; i < n; ++i) {
threadId[i] = i;
ptread_create(...., &threadId[i]);
}
如果将相同的参数传递给所有线程,那么i
上的拥塞就没有了。
答案 4 :(得分:0)
我真的不相信这是一个肮脏的黑客。维基百科在其pthreads example中也是如此。