C中的线程相互中断
Threads in C interrupt each other
所以我有一个名为 counter 的全局变量,我 运行 4 个线程以百万次递增,但我最后得到的结果甚至没有达到 200 万次。
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
int nthread;
int counter=0;
void *f(void *arg)
{
int i = *(int *)arg;
int *p;
for (int c = 0; c < 1000000; c++)
{
counter++;
}
printf(" I am thread %d (out of %d),tid =% ld\n", i, nthread, pthread_self());
p = malloc(sizeof(int));
*p = i * 2;
pthread_exit(p); // return p
}
int main(int argc, char *argv[])
{
pthread_t *tid;
int e, i, *ti;
nthread = 4;
tid = malloc(nthread * sizeof(pthread_t));
ti = malloc(nthread * sizeof(int));
for (i = 0; i < nthread; i++)
{
ti[i] = i;
if ((e = pthread_create(&tid[i], NULL, f, &ti[i])) != 0)
send_error(e, " pthread_create ");
}
for (i = 0; i < nthread; i++)
{
void *r;
if ((e = pthread_join(tid[i], &r)) != 0)
send_error(e, " pthread_join ");
printf(" Return of thread %d = %d\n", i, *(int *)r);
free(r);
}
printf("counter is %d\n",counter);
free(tid);
free(ti);
}
是什么原因造成的,我该如何解决?
PS:if 您的代码无法编译 将 send_error 替换为 printfs
pthreads 标准非常明确,您不能在一个线程中访问一个对象,而另一个线程正在或可能正在修改它。您的代码违反了这条规则。
这条规则有很多原因,但最明显的是:
for (int c = 0; c < 1000000; c++)
{
counter++;
}
您希望编译器像这样优化代码。您希望它将 counter
保存在寄存器中,或者如果可以的话甚至消除循环。但是如果没有避免线程重叠修改和访问同一对象的要求,编译器将不得不以某种方式证明任何其他线程中的其他代码都不能触及 counter
而此代码是 运行.
这将导致无法对 99% 的不跨线程共享对象的代码进行大量有价值的优化,因为编译器无法证明访问可能重叠。
要求 具有重叠对象访问权限的代码清楚地表明它们具有重叠对象访问权限更有意义。并且每个线程标准都提供了执行此操作的好方法,包括 pthreads。
您可以使用任何您喜欢的方法来防止这个问题。使用互斥量是最简单的,绝对是您应该首先学习的。
所以我有一个名为 counter 的全局变量,我 运行 4 个线程以百万次递增,但我最后得到的结果甚至没有达到 200 万次。
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
int nthread;
int counter=0;
void *f(void *arg)
{
int i = *(int *)arg;
int *p;
for (int c = 0; c < 1000000; c++)
{
counter++;
}
printf(" I am thread %d (out of %d),tid =% ld\n", i, nthread, pthread_self());
p = malloc(sizeof(int));
*p = i * 2;
pthread_exit(p); // return p
}
int main(int argc, char *argv[])
{
pthread_t *tid;
int e, i, *ti;
nthread = 4;
tid = malloc(nthread * sizeof(pthread_t));
ti = malloc(nthread * sizeof(int));
for (i = 0; i < nthread; i++)
{
ti[i] = i;
if ((e = pthread_create(&tid[i], NULL, f, &ti[i])) != 0)
send_error(e, " pthread_create ");
}
for (i = 0; i < nthread; i++)
{
void *r;
if ((e = pthread_join(tid[i], &r)) != 0)
send_error(e, " pthread_join ");
printf(" Return of thread %d = %d\n", i, *(int *)r);
free(r);
}
printf("counter is %d\n",counter);
free(tid);
free(ti);
}
是什么原因造成的,我该如何解决? PS:if 您的代码无法编译 将 send_error 替换为 printfs
pthreads 标准非常明确,您不能在一个线程中访问一个对象,而另一个线程正在或可能正在修改它。您的代码违反了这条规则。
这条规则有很多原因,但最明显的是:
for (int c = 0; c < 1000000; c++)
{
counter++;
}
您希望编译器像这样优化代码。您希望它将 counter
保存在寄存器中,或者如果可以的话甚至消除循环。但是如果没有避免线程重叠修改和访问同一对象的要求,编译器将不得不以某种方式证明任何其他线程中的其他代码都不能触及 counter
而此代码是 运行.
这将导致无法对 99% 的不跨线程共享对象的代码进行大量有价值的优化,因为编译器无法证明访问可能重叠。
要求 具有重叠对象访问权限的代码清楚地表明它们具有重叠对象访问权限更有意义。并且每个线程标准都提供了执行此操作的好方法,包括 pthreads。
您可以使用任何您喜欢的方法来防止这个问题。使用互斥量是最简单的,绝对是您应该首先学习的。