C 语言的 互斥锁、自旋锁、原子操作
创始人
2024-05-08 04:04:27
0

今天不整 GO 语言,我们来分享一下以前写的 C 代码,来看看 互斥锁,自旋锁和原子操作的 demo

互斥锁

临界区资源已经被1个线程占用,另一个线程过来访问临界资源的时候,会被CPU切换线程,不让运行后来的这个线程

适用于 锁住的内容多(例如红黑数的增加节点操作),切换线程的代价小于等待的代价

自旋锁

临界区资源已经被1个线程占用,另一个线程过来访问临界资源的时候,相当于是一个 while(1)

不断的查看这个资源是否可用,如果可用,就进去访问临界资源,如果不可用,则继续循环访问

适用于锁住的内容少,(例如就执行++操作),切换线程的代价大于等待的代价

原子操作

执行的操作完全不可分割,要么全部成功,要么全部失败

最好的方式就是适用原子操作

实操

需求场景:

1、用10个线程分别对 count 加 100000 次, 看看结果是否是 10*100000

  • main 函数中创建 10 个线程
  • 线程函数中调用 inc 做数据的增加
  • 分别使用 互斥锁,自旋锁,和原子操作,来进行控制

#include 
#include 
#include #define PTHREAD_NUM	10
#define INFO	printfpthread_mutex_t mutex;
pthread_spinlock_t spin;int inc(int *v,int add)
{int old;//汇编,做一个原子操作__asm__ volatile("lock;xaddl %2, %1;":"=a" (old):"m"(*v),"a"(add):"cc","memory");return old;
}void * thread_callback(void *arg)
{int *count = (int *)arg;int i = 100000;while(i--){#if 0
//互斥锁pthread_mutex_lock(&mutex);(*count)++;pthread_mutex_unlock(&mutex);#elif 0
//自旋锁pthread_spin_lock(&spin);(*count)++;pthread_spin_unlock(&spin);#else
//原子操作inc(count,1);#endifusleep(1);}}int main()
{pthread_t thread[PTHREAD_NUM] = {0};pthread_mutex_init(&mutex,NULL);pthread_spin_init(&spin,0);int count  = 0;for(int i = 0;ipthread_create(&thread[i],NULL,thread_callback,&count);}for(int i = 0;i<100;i++){INFO("count == %d\n",count);sleep(1);}return 0;
}

如上代码还是很简单的,感兴趣的 xdm 可以自行运行,控制自己使用互斥锁,自旋锁或者是原子操作看看效果进行对比一下

2、mutex、lock、atomic 性能对比

思路还是和上面的思路类型,咱们可以通过下面的代码来实际初步看看 mutex、lock、atomic 各自的性能

//并发
//互斥锁mutex
//	如果获取不到资源会让出cpu
//	使用场景
//		共享区域执行的内容较多的情况
//自旋锁spinlock
//	如果获取不到资源,会原地自旋,忙等
//	使用场景
//		共享区域执行的内容较少的情况
//原子操作
//	不可分割
//	使用场景
//		做简单++、--操作
//#include 
#include 
#include 
#include #define MAX_PTHREAD 2
#define LOOP_LEN    1000000000
#define LOOP_ADD    10000int count = 0;pthread_mutex_t mutex;
pthread_spinlock_t spin;typedef void *(*functhread)(void *arg);void do_add(int num)
{int sum = 0;for(int i = 0;isum +=i;}
}int atomic_add(int *v,int add)
{int old;__asm__ volatile("lock;xaddl %2, %1;":"=a" (old):"m"(*v),"a"(add):"cc","memory");return old;
}void * atomicthread(void *arg)
{for(int i  = 0;iatomic_add(&count,1);}
}void * spinthread(void *arg)
{for(int i  = 0;ipthread_spin_lock(&spin);count++;//do_add(LOOP_ADD);pthread_spin_unlock(&spin);}
}void * mutexthread(void *arg)
{for(int i  = 0;ipthread_mutex_lock(&mutex);count++;//do_add(LOOP_ADD);pthread_mutex_unlock(&mutex);}
}int test_lock(functhread thre,void * arg)
{clock_t start = clock();pthread_t tid[MAX_PTHREAD] = {0};for(int i = 0;i//创建线程int ret = pthread_create(&tid[i],NULL,thre,NULL);if(0 != ret){printf("pthread create rror\n");return -1;}}for(int i = 0;i
//回收线程pthread_join(tid[i],NULL);}clock_t end = clock();//printf("start  -- %ld\n",start);//printf("end  -- %ld\n",end);//printf("CLOCKS_PER_SEC  -- %ld\n",CLOCKS_PER_SEC);printf("spec lock is  -- %ld\n",(end - start)/CLOCKS_PER_SEC);}int main()
{pthread_mutex_init(&mutex,NULL);pthread_spin_init(&spin,0);
//测试spincount = 0;printf("use spin ------ \n");test_lock(spinthread,NULL);printf("count == %d\n",count);//测试mutexcount = 0;printf("use mutex ------ \n");test_lock(mutexthread,NULL);printf("count == %d\n",count);//测试atomiccount = 0;printf("use automic ------ \n");test_lock(atomicthread,NULL);printf("count == %d\n",count);return 0;
}

结果

通过上述结果,我们可以看到,加互斥锁,自旋锁,原子操作,数据都能如我所愿的累加正确,在时间上面他们还是有一定的差异:

自旋锁 和 互斥锁 在此处的案例性能差不多,但是原子操作相对就快了很多

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...