一个进程可以创建多个线程,这些线程的执行顺序是不确定的,但是相互独立。如果这些线程同时访问一个公共资源(例如,全局变量),这时可能会出现问题。
下面的例子中,开启了两个线程,每个线程中均对全局变量g_num执行自加一万此。理论上,最终的计算结果是20000,但实际运行结果与预想相差甚大。
#include <stdio.h> // printf fprintf
#include <stdlib.h> // EXIT_FAILURE EXIT_SUCCESS
#include <unistd.h> // sleep
#include <pthread.h> // pthread_create pthread_t
int g_num = 0;
void *start_routine_01(void *ptr)
{
for (size_t i = 0; i < 10000; i++)
g_num++;
return (void *)"8888";
}
void *start_routine_02(void *ptr)
{
for (size_t i = 0; i < 10000; i++)
g_num++;
return (void *)"9999";
}
int main(int argc, char const *argv[])
{
pthread_t thread_id_01;
pthread_t thread_id_02;
pthread_create(&thread_id_01, NULL, start_routine_01, NULL);
pthread_create(&thread_id_01, NULL, start_routine_02, NULL);
pthread_join(thread_id_01, NULL);
pthread_join(thread_id_02, NULL);
printf("计算结果为: %d\n", g_num);
printf("主线程即将退出...\n");
exit(EXIT_SUCCESS);
}
造成这种结果的原因为:g_num++操作并不是原子性的。数据操作的过程如下,先将数据的当前值从内存拷贝到寄存器,操作之后在从寄存器拷贝到内存中。多线程同时操作全局变量时,可能出现一下情况。例如,全局变量的当前值为1,线程一将数据从内存拷贝到寄存器0。由于线程调度还未执行自加操作,便开始执行其他任务。此时线程二亦开始操作该全局变量,并将该变量的值1拷贝到寄存器1,完成自加操作,并将结果2拷贝回内存。之后,线程一重新调度开始执行之前未完成的操作,将全局变量自加,并将结果拷贝回内存。这时发生了数据覆盖,新的计算结果将之前的计算结果覆盖掉。
本文通过一个C语言示例展示了多线程环境下全局变量自加操作导致的并发问题。由于g_num++不是原子操作,两个线程可能交错执行导致数据覆盖,从而使得最终结果与预期不符。这揭示了在多线程编程中需要考虑的数据同步和线程安全问题。
3973

被折叠的 条评论
为什么被折叠?



