我想了解下面的代码。这段代码没有竞争条件,但我无法理解。
#include <stdio.h>
#include <pthread.h>
void *foo(void *vargp) {
int id;
id = (int)vargp;
printf("Thread %d\n", id);
}
int main() {
pthread_t tid[2];
int i;
for (i = 0; i < 2; i++)
pthread_create(&tid[i], NULL, foo, (void *)i);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
从int
到void*
的类型转换是如何工作的?
答案 0 :(得分:1)
此代码说明了避免的竞争条件,这与原始代码非常相似,但略有不同,差异使其不正确:
/* Incorrect code! */
#include <pthread.h>
#include <stdio.h>
static void *foo(void *vargp)
{
int id = *(int *)vargp;
printf("Thread %d\n", id);
return 0;
}
int main(void)
{
pthread_t tid[2];
int i;
for (i = 0; i < 2; i++)
pthread_create(&tid[i], NULL, foo, &i); // Bad idea!
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
由于函数foo
采用void *
参数,因此将int
的地址传递给它是合乎逻辑的。但是,这有一个主要问题:
实际上,当我第一次运行此代码时,两个线程都报告了2
。
解决这个问题的方法是不传递i
的地址,而是按值传递i
。但是,参数仍然应该是void *
,因此代码在调用i
之前将void *
强制转换为pthread_create()
,并且线程函数撤消强制转换以检索值。
当我这样做时,我也使用<stdint.h>
使uintptr_t
类型可用,我使用:
int id = (uintptr_t)vargp;
和
pthread_create(&tid[i], NULL, foo, (void *)(uintptr_t)i);
看起来过分和/或过于强迫,但uintptr_t
强制转换确保整数与指针的大小相同,以避免'cast to pointer from integer of different size
'编译器警告(因为我告诉编译器将所有警告视为错误,对我来说是必要的,以便完全编译代码。
如果确实将指向数据的指针传递给线程函数(本讨论中为foo
),则必须确保您创建的每个线程都获得自己的数据副本,除非该数据是每个帖子都相同。
您可以在POSIX threads — unique execution中看到此技术。