我有一个模拟串行与并行计算的代码。但是,似乎有比赛条件。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
void *foo(void *para) {
printf("This is Thread %d running...\n", *(size_t *)para);
fflush(stdout);
sleep(2);
}
int main(void)
{
/* loop version
for (size_t i = 0; i < 4; i++) {
foo((void *)&i);
}
*/
pthread_t pool[4];
for (size_t i = 0; i < 4; i++) {
pthread_create(&pool[i], NULL, foo, (void *)&i);
}
for (size_t i = 0; i < 4; i++) {
pthread_join(pool[i], NULL);
}
return 0;
}
输出:
[william@Notebook Downloads]$ time ./a.out
This is Thread 1 running...
This is Thread 2 running...
This is Thread 4 running...
This is Thread 3 running...
real 0m2.003s
user 0m0.003s
sys 0m0.000s
[william@Notebook Downloads]$ time ./a.out
This is Thread 3 running...
This is Thread 3 running...
This is Thread 2 running...
This is Thread 4 running...
real 0m2.003s
user 0m0.003s
sys 0m0.000s
当竞争条件发生时,大多数示例都是在您有多个线程尝试编写共享值的情况下。但是,此代码中根本没有写操作。那么,为什么会这样呢?是因为for循环没有按顺序执行吗?
答案 0 :(得分:3)
我没有阅读您的问题。我只是看了一下您的代码,观察到发现了一个巨大的问题,这很可能是您所问问题的根本原因。看下面的循环代码:
pthread_t pool[4];
for (size_t i = 1; i <= 4; i++) {
pthread_create(&pool[i], NULL, foo, (void *)&i);
}
您有一个大小为4的“数组”,但是您正在遍历索引[1..4]
。 C和C ++数组从索引0开始,到(len-1)结束。换句话说,您应该遍历索引[0..3]。将任何内容插入pool[4]
都会创建未定义的行为。
代替此行:
for (size_t i = 1; i <= 4; i++) {
您想要这个:
for (size_t i = 0; i < 4; i++) {
对执行pthread_join
语句的第二个循环应用相同的修复程序。
还将&i
用作线程参数还会导致其他未定义的行为。您的线程正在访问一个变量的地址,该变量由主线程不断变化,然后超出范围。
答案 1 :(得分:3)
虽然较早的答案解决了您的代码问题,但这并不是您所要提出的问题的原由。
问题是您要向每个线程传递相同的参数。线程正在打印i
当时发生的任何事情,您不断更改的值。线程尝试访问它时,i
甚至可能不存在。
您需要传递不同的指针,而不是每次都传递相同的指针(例如,仅为线程分配的指针,或者指向数组的不同元素的指针,这些指针保证不会超出线程的寿命)。另外,由于指针本身是复制的,因此可以将足够小的整数强制转换为指针,然后让线程将指针强制强制转换为整数。