目录
1 进程线程间的互斥相关背景概念
2 互斥量mutex
3 互斥量的接口
4 加锁细节
5 互斥量实现原理探究
6 thread封装
7 mutex的封装
8 重入和线程安全
8.1 相关概念
8.2 常见线程不安全的情况
8.3 常见线程安全的情况
8.4 常见的不可重入的情况
8.5 常见的可重入的情况
8.6 可重入与线程安全联系
8.7 可重入与线程安全区别
9 常见锁概念
死锁
死锁四个必要条件
避免死锁
【代码举例】
模拟用户(一个线程一个用户)抢票问题
#include
#include
using namespace std;
#include
#include
int tickets = 1000; // 表示有这么多票
void *threadRoutine(void *args)
{
string name = static_cast(args);
while (true)
{
if (tickets > 0) // 表示有票
{
usleep(200); // 开始抢票前的工作
cout << name << " get a ticket:" << tickets-- << endl;
}
else
{
break;
}
}
}
int main()
{
pthread_t t[4]; // 四个线程模拟四个用户
int n = sizeof(t) / sizeof(t[0]);
for (int i = 0; i < n; ++i)
{
char *name = new char[64];
snprintf(name, 64, "thread:%d ", i + 1);
pthread_create(t + i, nullptr, threadRoutine, (void *)name);
}
for (int i = 0; i < n; ++i)
{
pthread_join(t[i], nullptr);
}
return 0;
}
提出问题:为什么出现了抢到票的编号为-1?也就是,没有票了为什么用户还能再继续抢票?
-- 操作并不是原子操作,而是对应三条汇编指令:
要解决以上问题,需要做到三点:
要做到这三点,本质上就是需要一把锁。Linux上提供的这把锁叫互斥量。
初始化互斥量
初始化互斥量有两种方法:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict
attr);
参数:
mutex:要初始化的互斥量
attr:NULL
销毁互斥量
销毁互斥量需要注意:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
互斥量加锁和解锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,失败返回错误号
调用 pthread_ lock 时,可能会遇到以下情况:
【改进抢票系统】
int tickets = 1000; // 表示有这么多票
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
void *threadRoutine(void *args)
{
string name = static_cast(args);
while (true)
{
int ret=pthread_mutex_lock(&mutex);
assert(ret==0);
(void)ret;
if (tickets > 0) // 表示有票
{
usleep(200); // 开始抢票前的工作
cout << name << " get a ticket:" << tickets-- << endl;
ret=pthread_mutex_unlock(&mutex);
assert(ret==0);
}
else
{
ret=pthread_mutex_unlock(&mutex);
assert(ret==0);
break;
}
usleep(100);
}
}
int main()
{
//pthread_mutex_init(&mutex,nullptr);
pthread_t t[4]; // 四个线程模拟四个用户
int n = sizeof(t) / sizeof(t[0]);
for (int i = 0; i < n; ++i)
{
char *name = new char[64];
snprintf(name, 64, "thread:%d ", i + 1);
pthread_create(t + i, nullptr, threadRoutine, (void *)name);
}
for (int i = 0; i < n; ++i)
{
pthread_join(t[i], nullptr);
}
//pthread_mutex_destroy(&mutex);
return 0;
}
这样就能确保抢票的准确性!
#pragma once
#include
#include
#include
#include
class thread
{
public:
typedef enum
{
NEW=0,
RUN,
EXIT
}ThreadStatus;
public:
thread(int num,std::function func_t,void* args)
:_func_t(func_t)
,_id(0)
,_args(args)
,_status(NEW)
{
char buffer[64];
snprintf(buffer,sizeof(buffer),"thread:%d ",num);
std::string name=buffer;
_name=move(name);
}
static void* runHelp(void* args)
{
thread* t=static_cast(args);
(*t)();
return nullptr;
}
void operator()()
{
if(_func_t!=nullptr)_func_t(_args);;
}
void run()
{
int ret=pthread_create(&_id,nullptr,runHelp,this);
if(ret!=0)
{
cout<<"create error"< _func_t;
std::string _name;
pthread_t _id;
void* _args;
ThreadStatus _status;
};
#pragma once
#include
class Mutex
{
public:
Mutex(pthread_mutex_t* mutex):_pmutex(mutex)
{}
void lock()
{
pthread_mutex_lock(_pmutex);
}
void umlock()
{
pthread_mutex_unlock(_pmutex);
}
private:
pthread_mutex_t* _pmutex;
};
class LockGuard
{
public:
LockGuard(pthread_mutex_t* mutex):_mutex(mutex)
{
_mutex.lock();
}
~LockGuard()
{
_mutex.umlock();
}
private:
Mutex _mutex;
};
概念:死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态。(可能由一个或者多个锁导致死锁)