线程:线程是进程资源分配的最小单位,每个进程都有的自己的main(主线程)
线程同步:多个线程按顺序以此执行访问共享资源(数据)。
线程同步的必要性:防止多线程并发访问共享数据的时候出现数据混乱、不一致的问题。
线程同步的方法:互斥锁、自旋锁、条件变量....
实例:创建两个线程轮流计数
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<pthread.h> int q_cont; //计数值 long loops; //计数次数 void *task(void *arg) { long num=(long)arg; int j_cont=0; int i; for(i=0;i<num;i++) //单线程循环loops次 { //计数 j_cont=q_cont; j_cont++; q_cont=j_cont; } pthread_exit(NULL); } int main(int aegc,char *argv[]) { int i; pthread_t tid1,tid2; loops=atoi(argv[1]); //创建线程 pthread_create(&tid1,NULL,task,(void *)loops); pthread_create(&tid2,NULL,task,(void *)loops); //等待线程结束 pthread_join(tid1,NULL); pthread_join(tid2,NULL); //打印次数 printf("q_cont=%d\r\n",q_cont); return 0; }
一、自旋锁基本简介
自旋锁本质上是一把锁,在访问共享资源之前对自旋锁进行上锁,在访问完成后释放自旋锁(解锁);
从实现方式上来说,互斥锁是基于自旋锁来实现的,所以自旋锁相比较于互斥锁更加底层。
二、自旋锁和互斥锁之间的区别
互斥锁 |
自旋锁 |
等待方式 |
阻塞(休眠) |
自旋(不停申请) |
效率 |
低(休眠、唤醒开销大) |
高 |
应用场景 |
进程上下文 |
中断上下文 |
缺点 |
|
自旋占用CPU资源,不适用于长时间等待 |
三、自旋锁API函数
1、pthread_spin_init() 初始化函数
原型:int pthread_spin_init(pthread_spinlock_t *lock ,int pshared);
参数:pthread_spinlock_t *lock pthread_spinlock_t 定义的锁
int pshared PTHREAD_PROCESS_PRIVATE
PTHREAD_PROCESS_SHARED
PTHREAD_PROCESS_PRIVATE 自旋锁只能在同一进程中的线程进行操作。
PTHREAD_PROCESS_SHARED 自旋锁可以由任何进程中的任何线程操作。
2、pthread_spin_lock(pthread_spinlock_t *lock) 加锁函数
3、pthread-spin_unlock(pthread_spinlock_t *lock) 解锁函数
4、pthread_spin_destroy(pthread_spinlock_t *lock) 摧毁锁函数
补充:
pthread_spin_trylock(pthread_spinlock_t *lock) 加锁函数
函数对自旋锁进行加锁,如果未能获取到锁,就立刻返回错误,错误码为 EBUSY。
互斥锁API函数
- pthread_mutex_init(pthread_mutex_t*mutex,constpthread_mutexattr_t mutexattr) 初始化函数
- Pthread_mutex_lock(pthread_mutex_t *mutex) 加锁函数
- Pthread_mutex_unlock(pthread_mutex_t *mutex) 解锁函数
- Pthread_mutex_destroy(pthread_mutex_t *mutex) 摧毁锁
四、自旋锁代码实现
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<pthread.h> int q_cont; //计数值 long loops; //循环计数次数 pthread_spinlock_t spin; void *task(void *arg) { long num=(long)arg; int j_cont=0; int i; for(i=0;i<num;i++) //循环loops次 { //加锁 pthread_spin_lock(&spin); j_cont=q_cont; j_cont++; q_cont=j_cont; //解锁 pthread_spin_unlock(&spin); } pthread_exit(NULL); } int main(int aegc,char *argv[]) { int i; pthread_t tid1,tid2; loops=atoi(argv[1]); //初始化自旋锁 pthread_spin_init(&spin,PTHREAD_PROCESS_PRIVATE); //创建线程 pthread_create(&tid1,NULL,task,(void *)loops); pthread_create(&tid2,NULL,task,(void *)loops); //等待线程 pthread_join(tid1,NULL); pthread_join(tid2,NULL); //摧毁锁 pthread_spin_destroy(&spin); printf("q_cont=%d\r\n",q_cont); return 0; }
五、互斥锁实现
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<pthread.h> int q_cont; //计数值 long loops; //计数次数 pthread_mutex_t lock; void *task(void *arg) { long num=(long)arg; int j_cont=0; int i; for(i=0;i<num;i++) //单线程循环loops次 { //加锁 pthread_mutex_lock(&lock); //计数 j_cont=q_cont; j_cont++; q_cont=j_cont; //解锁 pthread_mutex_unlock(&lock); } pthread_exit(NULL); } int main(int aegc,char *argv[]) { int i; pthread_t tid1,tid2; loops=atoi(argv[1]); //互斥锁初始化 pthread_mutex_init(&lock,NULL); //创建线程 pthread_create(&tid1,NULL,task,(void *)loops); pthread_create(&tid2,NULL,task,(void *)loops); //等待线程结束 pthread_join(tid1,NULL); pthread_join(tid2,NULL); //摧毁锁 pthread_mutex_destroy(&lock); //打印次数 printf("q_cont=%d\r\n",q_cont); return 0; }
运行结果:
不加锁:
加锁后:
总结:
将互斥锁替换为自旋锁之后,测试结果打印也是没有问题的,并且通过对比可以发现,替换为自旋锁之后,程序运行所耗费的时间明显变短了,说明自旋锁确实比互斥锁效率要高。