线程安全概念:多线程环境中 , 且存在数据共享 , 一个线程访问的共享 数据被其他线程修改了, 那么就发生了线程安全问题 , 整个访问过程中 , 无一共享的数据被其他线程修改了 就是线程安全的,程序中如果使用成员变量, 且对成员变量进行数据修改 , 就存在数据共享问题, 也就是线程安全问题。
线程不安全出现的原因:当多个线程同时共享一个全局变量,或者静态变量, 当某个线程正在对共享数据进行修改时,其他的线程也在对该数据进行写或者取操作,导致数据错误。(即多线程并发)
Linux操作系统下的实例:
#include<stdio.h>//线程不安全
#include<pthread.h>
#include<unistd.h>
int a;
void* exproc(void *arg){
for(int i=0;i<25000;i++){
a++;
}
}
int main(){
const int numThreads=4;
//创建线程
pthread_t threads[numThreads];
for (int i = 0; i < numThreads; i++) {
pthread_create(&threads[i], NULL, exproc, NULL);
}
// 主线程等待所有子线程结束
for (int i = 0; i < numThreads; i++) {
pthread_join(threads[i], NULL);
}
printf("a的数值:%d\n",a);
return 0;
}
输出结果:
在该实例中,由于四个线程对于全局变量a的操作都不是原子性操作,如果有一定汇编基础的话,我们就可以知道,在a++的过程中,对a是读取,修改,写入的过程。当多个线程进行a++的时候,由于不是原子性操作,就导致了指令的冲突。进而导致最终结果多数情况下不是10万
解决方案:
在C或者C++中,我们可以通过使用信号量(semaphore)来解决这一问题,信号量是操作系统中用来解决并发中的互斥或者同步问题的一个方法。详情见信号量部分。
修改后的代码:
#include<stdio.h>//使用信号量解决线程不安全
#include<pthread.h>
#include<unistd.h>
#include<semaphore.h>
int a;
sem_t sempb;
void* exproc(void *arg){
sem_wait(&sempb);
for(int i=0;i<25000;i++){
a++;
}
sem_post(&sempb);
}
int main(){
sem_init(&sempb,0,1);
const int numThreads=4;
//创建线程
pthread_t threads[numThreads];
for (int i = 0; i < numThreads; i++) {
pthread_create(&threads[i], NULL, exproc, NULL);
}
// 主线程等待所有子线程结束
for (int i = 0; i < numThreads; i++) {
pthread_join(threads[i], NULL);
}
printf("a的数值:%d\n",a);
sem_destroy(&sempb);
return 0;
}
结果: