#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <pthread.h>
/*自旋锁,是属于busy-waiting类型的锁.在多处理器环境中, 自旋锁最多只能被一个可执行线程持有。
* 如果一个可执行线程试图获得一个被争用(已经被持有的)自旋锁,那么该线程就会一直进行忙等待,自旋,也就是空转,等待锁重新可用。
* 如果锁未被争用,请求锁的执行线程便立刻得到它,继续执行。
*一个被争用的自旋锁使得请求它的线程在等待锁重新可用时自旋,特别的浪费CPU时间,所以自旋锁不应该被长时间的持有。
* 实际上,这就是自旋锁的设计初衷,在短时间内进行轻量级加锁。
背景和定义
自旋锁它是为为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。
两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁(忙循环)
2、自旋锁适用情况
自旋锁比较适用于锁使用者保持锁时间比较短的情况。
正是由于自旋锁使用者一般保持锁时间非常短,自旋锁的效率远高于互斥锁。
信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用,而自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用。如果被保护的共享资源只在进程上下文访问,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。
自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。
单CPU非抢占内核下:自旋锁会在编译时被忽略(因为单CPU且非抢占模式情况下,不可能发生进程切换,时钟只有一个进程处于临界区(自旋锁实际没什么用了)
单CPU抢占内核下:自选锁仅仅当作一个设置抢占的开关(因为单CPU不可能有并发访问临界区的情况,禁止抢占就可以保证临街区唯一被拥有)
多CPU下:此时才能完全发挥自旋锁的作用,自旋锁在内核中主要用来防止多处理器中并发访问临界区,防止内核抢占造成的竞争。
操作是原子的,因为当多个线程在给定时间自旋,也只有一个线程可以获得该锁。
3、自旋锁有几个重要的特性
1、被自旋锁保护的临界区代码执行时不能进入休眠。
2、被自旋锁保护的临界区代码执行时是不能被被其他中断中断。
3、被自旋锁保护的临界区代码执行时,内核不能被抢占。
4、在自旋锁忙等期间,因为并没有进入临界区,所以内核抢占还是有效的,因此,等待自旋锁释放的进程有可能被更高优先级的所取代
5、存在两个问题:死锁和过多占用cpu资源。
从这几个特性可以归纳出一个共性:被自旋锁保护的临界区代码执行时,它不能因为任何原因放弃处理器。
自旋锁和互斥锁对比
Mutex(互斥锁):
sleep-waiting类型的锁
对于自旋锁来说,它只需要消耗很少的资源来建立锁;随后当线程被阻塞时,它就会一直重复检查看锁是否可用了,也就是说当自旋锁处于等待状态时它会一直消耗CPU时间。
互斥锁适用于那些可能会阻塞很长时间的场景。
1、 临界区有IO操作
2 、临界区代码复杂或者循环量大
3 、临界区竞争非常激烈
4、 单核处理器
Spin lock(自旋锁)
busy-waiting类型的锁
与自旋锁相比它需要消耗大量的系统资源来建立锁;随后当线程被阻塞时,线程的调度状态被修改,并且线程被加入等待线程队列;最后当锁可用时,在获取锁之前,线程会被从等待队列取出并更改其调度状态;但是在线程被阻塞期间,它不消耗CPU资源。
自旋锁适用于那些仅需要阻塞很短时间的场景
*/
pthread_spinlock_t spinlock;
int data;
//线程工作函数
void *thread_work_func(void *dev)
{
while(1)
{
pthread_spin_lock(&spinlock); //上锁
printf("data=%d\n",data);
pthread_spin_unlock(&spinlock); //解锁
sleep(1);
}
}
//线程工作函数
void *thread_work_func2(void *dev)
{
while(1)
{
pthread_spin_lock(&spinlock); //上锁
data++;
pthread_spin_unlock(&spinlock); //解锁
sleep(1);
}
}
int main(int argc,char **argv)
{
//初始化自旋锁
pthread_spin_init(&spinlock,PTHREAD_PROCESS_PRIVATE);
/*1. 创建子线程1*/
pthread_t thread_id;
if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0)
{
printf("子线程1创建失败.\n");
return -1;
}
/*2. 创建子线程2*/
pthread_t thread_id2;
if(pthread_create(&thread_id2,NULL,thread_work_func2,NULL)!=0)
{
printf("子线程2创建失败.\n");
return -1;
}
/*3. 等待线程的介绍*/
pthread_join(thread_id,NULL);
pthread_join(thread_id2,NULL);
//销毁自旋锁
pthread_spin_destroy(&spinlock);
return 0;
}
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
pthread_test.zip (49个子文件)
pthread_test
pthread_test.pro.user 59KB
Makefile 71KB
pthread_sem
Makefile 44KB
pthread_sem 13KB
pthread_sem.pro 113B
main.o 4KB
main.c 2KB
pthread_spinlock
Makefile 44KB
pthread_spinlock 12KB
pthread_spinlock.pro 113B
main.o 9KB
main.c 6KB
pthread_rwlock
Makefile 44KB
pthread_rwlock 17KB
pthread_rwlock.pro 113B
main.o 11KB
main.c 3KB
pthread_cond
Makefile 44KB
pthread_cond 17KB
main.o 11KB
main.c 1KB
pthread_cond.pro 113B
pthread_stacksize
Makefile 44KB
pthread_stacksize 11KB
main.o 7KB
main.c 998B
pthread_stacksize.pro 114B
pthread_mutex
Makefile 44KB
pthread_mutex.pro 113B
pthread_mutex 16KB
main.o 10KB
main.c 1KB
pthread_barrier
Makefile 44KB
pthread_barrier 13KB
main.o 3KB
pthread_barrier.pro 113B
main.c 2KB
.qmake.stash 739B
pthread_creat
Makefile 44KB
pthread_creat.pro 113B
main.o 9KB
main.c 2KB
pthread_creat 12KB
pthread_test.pro 215B
socketpair
Makefile 44KB
socketpair.pro 114B
main.o 9KB
main.c 2KB
socketpair 16KB
共 49 条
- 1
资源评论
bugmaker01
- 粉丝: 11
- 资源: 18
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功