线程安全
线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。
简单点来说: 因为多线程为一个进程下的多个执行流, 那么就意味着这些线程都共用同一份虚拟地址空间, 这样以来个个线程之间就会有很多数据是共享的 , 比如全局数据, 堆上的内存, 而如果多个线程同时操作一个这样的资源, 那么就会出现不可预知的结果, 比如如下的抢票程序
如何实现线程安全
同过同步与互斥可以实现线程安全
可以看一下的实例:
#include <iostream>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
using namespace std;
int ticket = 100;
//thread_mutex_t mutexs;
void* TekeTi(void* agr)
{
while(1)
{
// pthread_mutex_lock(&mutexs);
if(ticket>0)
{
printf("我抢到%d,我是线程%ld\n", ticket, (long)agr);
ticket--;
usleep(10);
// pthread_mutex_unlock(&mutexs);
}
else
{
cout<<"pthrea"<<(long)agr<<endl;
// pthread_mutex_unlock(&mutexs);
return NULL;
}
}
}
int main()
{
pthread_t tid[4];
// pthread_mutex_init(&mutexs, NULL);
for(int i=0;i<4;i++)
{
pthread_create(&tid[i], NULL, TekeTi, (void*)i);
}
for(int i=0;i<4;i++)
{
pthread_join(tid[i],NULL);
}
return 0;
}
运行结果:
互斥锁
目的: 将临界资源只让一个线程访问, 就像一个人上厕所把门先关上, 别人就进不来, 上完厕所了, 然后再把门打开 , 实现互斥功能, 这个资源一个线程访问了, 另一个线程不能访问
互斥锁初始化
pthread_mutex_t 为互斥锁变量类型
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
初始化有两种方法第一种直接让其等于一个宏这样这样的好处是不用手动释放
第二种方法就是通过初始化函数,函数第一个参数为互斥锁变量, 第二个为属性信息一般置为空
互斥量加锁和解锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);// 返回值:成功返回0,失败返回错误号
注:互斥量处于未锁状态,该函数会将互斥量锁定,同时返回成功 发起函数调用时,其他线程已经锁定互斥量,或者存在其他线程同时申请互斥量,但没有竞争到互斥 量,那么pthread_ lock调用会陷入阻塞(执行流被挂起),等待互斥量解锁。
销毁互斥量
int pthread_mutex_destroy(pthread_mutex_t *mutex);
注意:1)使用 PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要销毁
2)不要销毁一个已经加锁的互斥量
3)已经销毁的互斥量,要确保后面不会有线程再尝试加锁
互斥锁实现原理: 内存数据要进行修改的时候一般先将数据加载到CPU寄存器中, 在然后修改数据在存入内存, 而互斥锁底层中将0/1这个计数器数字写入寄存器,在寄存器中设置为0, 然后和内存中的数据进行交换, 那么内存中的值一定为0, 而自己在可以判断是否可继续操作.
考虑线程安全
将上述代码中的注释都放开, 重新编译运行结果如下