目录
什么是线程安全问题?
线程安全问题是指在多线程环境下,当多个线程访问共享资源可能会导致的数据不一致问题。
一.多线程抢票问题:
以下面的多线程抢票代码为例:
#include<iostream>
#include<stdio.h>
using namespace std;
int tickets=10000;
void* threadroutine(void* arg)
{
char* name=(char*)arg;
while(true)
{
if(tickets>0)
{
cout<<name<<" get a ticket :"<<tickets<<endl;
tickets--;
}
else
break;
}
return nullptr;
}
int main()
{
pthread_t tids[5];
//创建线程
for(int i=0;i<5;i++)
{
char name[32];
sprintf(name,"%s%d","thread-",i+1);
pthread_create(&tids[i],nullptr,threadroutine,(void*)name);
}
//等待线程
for(int i=0;i<5;i++)
pthread_join(tids[i],nullptr);
return 0;
}
代码执行结果:
为什么会出现抢到负数票的问题呢?
多个线程都执行这个抢票代码,由于线程之间可能是并行的,在票数为1时,多个线程都判断到tickets>0,于是每个线程都进入了if语句里,进而多抢了票。
线程之间可能是并发的,一个线程执行完判断逻辑为true,还没来得及对tickets--就切换了,下一个线程判断tickets依然大于0,于是就有多个线程进入抢不够的票。
二.单核CUP上线程并发没有并行也会引发线程安全问题
举例说明
i++本质也不是线程安全的(不是原子的):
线程a、b并发执行时,线程a先执行第一步将 i 放入AL中,第二步加法器++,此时线程突然被切走带走自己的硬件上下文(由于未进行第三步,内存中的i还未成功++),b线程开始执行,b线程执行完毕,内存中的i变为1,然后a线程又被调度,将自己的硬件上下文拷回寄存器,AL中的值为1,再接着上次的进度执行第三步,将1拷回内存,内存中的i最终为1。但我们想要的结果一定是2,由于两个线程对共享资源i的访问不是原子的