我正在研究 Linux 和操作系统中使用的线程。我正在做一些运动。目标是对一个全局变量的值求和,最后查看结果。当我看到最后的结果时,我的心就炸了。代码如下
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
int i = 5;
void *sum(int *info);
void *sum(int *info)
{
//int *calc = info (what happened?)
int calc = info;
i = i + calc;
return NULL;
}
int main()
{
int rc = 0,status;
int x = 5;
pthread_t thread;
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
rc = pthread_create(&thread, &attr, &sum, (void*)x);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
rc = pthread_join(thread, (void **) &status);
if (rc)
{
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("FINAL:\nValue of i = %d\n",i);
pthread_attr_destroy(&attr);
pthread_exit(NULL);
return 0;
}
如果我将变量 calc 作为 int *cal 放在 sum 函数中,那么 i 的最终值是 25(不是预期值)。但是如果我把它作为 int calc 那么我的最终值是 10(我在这个练习中的期望值)。我不明白当我将变量 calc 设为 int *calc 时,i 的值怎么会是 25。
阅读一些关于 pthreads 的教程。在多个线程中访问和修改全局数据时,您不能期望可重现的行为(没有与同步相关的额外编码预防措施)。AFAIU 您的代码表现出一些棘手的未定义行为,您应该感到害怕(也许在您的情况下这只是未指定的行为)。要解释观察到的具体行为,您需要深入研究实现细节(而您没有时间这样做:研究生成的汇编代码、特定硬件的行为等……)。
另外(因为info
是指向an的指针int
)
int calc = info;
没有多大意义(我猜你打错了)。在某些系统上(比如我的 x86-64 运行 Linux),指针比 an 宽int
(因此从 中calc
丢失了一半的位info
)。在其他(稀有)系统上,它的尺寸可能更小。有时(运行 Linux 的 i686)它可能具有相同的大小。您应该考虑intptr_t
from<stdint.h>
是否要将指针转换为整数值并返回。
实际上,您应该使用mutex保护对全局数据(内部i
,可能通过指针访问)的访问,或者在 C11原子操作中使用,因为该数据由多个并发线程使用。
所以你可以声明一个全局互斥锁
pthread_mutext_t mtx = PTHREAD_MUTEX_INITIALIZER;
(或使用pthread_mutex_init)然后在你的sum
代码中
pthread_mutex_lock(&mtx);
i = i + calc;
pthread_mutex_unlock(&mtx);
(另见pthread_mutex_lock和pthread_mutex_lock(3p))。当然你也应该在你的main
.
锁定互斥锁有点昂贵(通常是添加的几十倍),即使在它被解锁的情况下也是如此。如果您可以在 C11 中编码,您可能会考虑原子操作,因为您处理整数。您将声明atomic_int i;
并在其上使用atomic_load和atomic_fetch_add。
如果您好奇,另请参阅pthreads(7)和futex(7)。
多线程编程真的很难(对所有人来说)。您不能期望行为在一般情况下是可重现的,并且您的代码显然可以按预期运行但仍然非常错误(并且在某些不同的系统上会以不同的方式工作)。另请阅读有关内存模型、CPU 缓存、缓存一致性、并发计算...
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句