一、为什么要锁

锁是为了防止多线访问共同内存时的冲突问题,先看实例:两个线程分别对全局变量累加:

//gcc lock_test.c -lpthread
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
​
int num = 0; //设置为全局变量,在全局区域共享
​
void* myfun(void* arg);
​
pthread_mutex_t mtx;
int main()
{
 //1.产生两个线程,分别对全局变量累加
 pthread_t id[2];
 pthread_mutex_init(&mtx,NULL);
 for (int i = 0; i < 2; i++) {
 pthread_create(&(id[i]), NULL, myfun, NULL);
 }

 pthread_join(id[0],NULL); 
 pthread_join(id[1],NULL); 
 printf("%d\n",num);
 return 0;
​
}
​
void* myfun(void* arg)
{
 int i;
 for(i=0;i<100000000;i++){
//  pthread_mutex_lock(&mtx);
 num++;
//  pthread_mutex_unlock(&mtx); 
 }

 return NULL;
}

如果没有加锁,num的结果每次都不一样:

lock1.jpg

如果加锁(myfun的注释部分),最后的结果才正确,但时间会更长。

lock2.jpg

二、锁竞争的妙用

回顾C++多线程前面三篇的例子,我们都是给固定的线程分配任务,然后每个线程完成任务后就销毁,但是如果每个任务的计算量不一样,那么就会造成负载不均衡,先完成任务的线程不能“帮助”后完成任务的线程。

现实生活中,一群人干活,干的快的可以帮助干的慢的,那么在多线程的框架下如何实现呢?

这时候,“锁”的妙用来了!假设我们的任务时计算一万个矩阵的逆,各矩阵间不相关,但大小不一,比较随机。如何让这些线程“互帮互助”呢?

一个很巧妙的方式是,我们仍然设置一个全局累加变量,但需要稍微修改改myfun:

void* myfun(void* arg)
{
 int i;
 while(1){
 pthread_mutex_lock(&mtx);
 i = num;
 if(i>=10000){
 pthread_mutex_unlock(&mtx);
 break;
 }
 num++;
 pthread_mutex_unlock(&mtx);
 task_invmatrix[i];//执行第i个任务
}

各个线程先争夺全局变量num,修改num之后,执行第i(=num)个任务,由于任务的时间远大于加锁、修改num、解锁的时间,这样便实现了各线程的互帮互助!

更多实例可以参看我的gitee:ptread_lock

标签: 算法, C++, 锁竞争

添加新评论