我在多线程方面遇到了问题。请考虑以下代码:
#include<stdio.h>
#include<pthread.h>
void* functionA(void*);
void* functionB(void*);
int main()
{
pthread_t tid[2];
pthread_attr_t arg;
for(int i = 0; i<2; ++i)
{
pthread_attr_init(&arg);
if(i == 0)
{
int x = 0;
pthread_create(&tid[i], &arg, functionA, (void*)&x);
}
else if(i == 1)
{
int x = 6;
pthread_create(&tid[i], &arg, functionB, (void*)&x);
}
}
// wait for both threads to finish execution...
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
//.........................DEFINATIONS........................
void* functionA(void* x)
{
int Index = *((int*)x);
printf("First: %d\n",Index); //..................... LINE M
}
void* functionB(void* x)
{
int Index = *((int*)x);
printf("Second: %d\n",Index); //....................... LINE N
}
现在我相信functionA将首先开始执行,因为函数A的求助线程将首先在for循环中创建,所以根据我的输出应该是:
First: 0 (from Line M)
Second: 6 (from Line N)
但实际输出是,
Second: 6
First: 6
现在我很惊讶地看到这一点,我不知道发生了什么。不仅secondFunction首先开始执行,而且两个函数都显示相同的值,即6,这对我来说没有意义。任何人都可以请你解释一下这里发生了什么???? 提前谢谢......
答案 0 :(得分:3)
两件事
1)这里x变量范围仅限于块if。所以在您的线程函数中,当您访问该指针时,其范围已经消失所以您在线程函数中访问非法内存是错误的,它将创建未定义的行为。
回应您的一条评论
所以有没有办法代替变量,我可以直接发送一个常数,例如pthread_create(&amp; tid [i],&amp; arg,functionA,6)??
POSIX线程是一个C API。 C不提供类似的语言设施 复制构造函数,因此无法复制任何对象 值。
您需要始终按指针传递内容。
2)执行线程的优先级是完全操作系统和调度程序依赖,你不能假设这些线程的序列。
你仍然希望线程之间有一些同步,然后使用互斥,条件变量等。
答案 1 :(得分:2)
您将指向短期局部变量的指针传递给线程,一旦这些范围退出就会导致未定义的行为。可能两个线程都看到x
的相同地址。
最明显的解决方法是为变量使用更高的范围,并且每个线程都有一个包含整数的数组:
pthread_t tid[2];
pthread_attr_t arg;
int x[2] = { 0, 6 };
void * (*func[])(void *) = { functionA, functionB };
for(int i = 0; i < 2; ++i)
{
pthread_attr_init(&arg);
pthread_create(&tid[i], &arg, func[i], &x[i]);
}
// wait for both threads to finish execution...
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
这是有效的,因为x
数组将通过pthread_join()
的调用。也无需强制转换指针,int *
会自动转换为C中的void *
。
此外,关于线程开始顺序的假设是错误的,没有这样的保证。
答案 2 :(得分:2)
无法保证它们的运行顺序。在创建线程时,操作系统的调度程序将注册新线程并在有时间时运行它。基于系统上的优先级和其他hings,它可以按任何顺序选择它们,即中断主线程并启动其他线程,或运行主线程直到连接,然后启动任何其他线程。
您可能正在多核系统上进行测试。那些甚至可能同时并行运行,但由于某种原因,一个或另一个可能更快(可能第二个数据在缓存中,而第一个必须从内存中获取数据?)
长话短说:无法保证。
如果您需要特定订单,您可以使用锁(即互斥)来强制执行同步,或者您可以设置优先级(请参阅setpriority())或强制实时调度(sched_setscheduler())但是您真的应该了解您的操作系统
答案 3 :(得分:0)
我相信functionA会先开始执行,因为 函数A的当前线程将首先在for循环中创建
这种假设不正确,这取决于OS控制的线程调度。
如果要查看正确的输出,请在main()
函数范围内声明两个变量(在for
循环之前)
int x = 0;
int y = 6;
并在
中进行更改pthread_create(&tid[i], &arg, functionA, (void*)&x);
pthread_create(&tid[i], &arg, functionB, (void*)&y);
通过这样做,你至少得到正确的输出。