目录
1.为什么要线程同步
多个线程同时对内存中的共享资源进行访问时,当一个线程对共享资源进行修改时,其他线程得到的依然是修改前的内容,这样就存在巨大的隐患
比如三个ABC人共用一张银行卡,这三个人就是三个线程,银行卡就是共享资源,假如银行卡里有100块钱,这三个人同时取这100块钱,如果不做线程同步,那么三个人都能同时从卡里取出100块钱,也就是总共取出300块钱,那银行岂不是血亏
所以线程同步就是多个线程同时对共享内存提出访问申请时,需要按照先后次序进行访问(线性访问),就是说当A正在取钱时,BC就要等待A取完才能取
未进行线程同步的代码示例(刷银行卡的例子):
int card;
void* aGetMoney(void* arg)
{
ostringstream* str = (ostringstream*)arg;
(*str) << "a check: " << card;
card = 0;
return NULL;
}
void* bGetMoney(void* arg)
{
ostringstream* str = (ostringstream*)arg;
(*str) << "b check: " << card;
card = 0;
return NULL;
}
void* cGetMoney(void* arg)
{
ostringstream* str = (ostringstream*)arg;
(*str) << "c check: " << card;
card = 0;
return NULL;
}
int main(int argc, char** argv)
{
card = 100;
ostringstream stra, strb, strc;
pthread_t tida, tidb, tidc;
pthread_create(&tida, NULL, aGetMoney, &stra);
pthread_create(&tidb, NULL, bGetMoney, &strb);
pthread_create(&tidc, NULL, cGetMoney, &strc);
pthread_join(tida, NULL);
pthread_join(tidb, NULL);
pthread_join(tidc, NULL);
cout << stra.str() << endl;
cout << strb.str() << endl;
cout << strc.str() << endl;
return 0;
}
结果:
a check: 100
b check: 100
c check: 100
可以看到,未进行线程同步时,即使卡里只有100块钱,ABC可以同时取到100块钱,这是银行不希望看到的
2.线程同步的方式
线程同步的方式有四种:互斥锁、读写锁、条件变量、信号量
共享资源也称为临界资源(一般为全局区或堆区资源),临界资源相关的上下文代码成为临界区
线程同步的本质就是临界区最多同时只能有一个线程访问
对于上述例子,银行卡就是临界资源,对银行卡的存取操作就是临界区,也就是说某一个时间最多只能有一个人对银行卡进行操作
2.1互斥锁
互斥锁就是在临界区的开头加锁,末尾解锁,一个线程加锁操作后,其他线程不能再加锁将被阻塞,直到这个锁被解开,其他线程解除阻塞后再去竞争资源。类比排队上厕所
一般一个临界资源对应一把互斥锁,哪个线程加的锁,哪个线程解锁,就比如上厕所,你进去把门锁上了,别人也不能从外面解锁打开门,更不能再锁一次门
锁的个数一般看共享资源的个数
(1)创建互斥锁:
pthread_mutex_t mutex;
(2)初始化互斥锁:
int pthread_mutex_init(pthread_mutex_t* restrict mutex,
const pthread_mutexattr_t* restrict attr);
参数:
* restrict mutex:互斥锁的地址
* restrict attr:属性,默认为NULL
(3)释放互斥锁资源
int pthread_mutex_destroy(pthread_mutex_t *mutex);
(4)加锁
int pthread_mutex_lock(pthread_mutex_t* mutex);
一个线程执行到这里时会判断mutex是不是锁定状态,如果已被锁了则线程阻塞在这里,如果没被锁则线程可以加锁
(5)解锁
int pthread_mutex_unlock(pthread_mutex_t* mutex);
举例:还是上面银行卡的例子,对临界区加锁之后,可以看到,当卡里的钱被a取完后,bc再查卡里就没钱了
int card;
pthread_mutex_t mutex;
void* aGetMoney(void* arg)
{
ostringstream* str = (ostringstream*)arg;
pthread_mutex_lock(&mutex);
(*str) << "a check: " << card;
card = 0;
pthread_mutex_unlock(&mutex);
return NULL;
}
void* bGetMoney(void* arg)
{
ostringstream* str = (ostringstream*)arg;
pthread_mutex_lock(&mutex);
(*str) << "b check: " << ca