Linux 同步和互斥

当我们在某个独立的main.c中对一个共享资源读写的时候,为了防止其他模块也在同步修改,往往会维护一个全局flag,如下:
if(flag==TRUE)
{
//read or write value;
flag = FALSE;
}
但是在多进程中,read or write过程中可能进程被调度出去,此时flag还是TRUE,其他进程也可能会修改这个变量,从而实现不了同步和互斥的作用.

那么同步和互斥,主要有以下方面的内容:
1.进程与进程之间的同步互斥.
2.进程与其他代码之间
3.进程与中断之间.

Linux的同步机制主要有:
1.信号量(struct semaphore)
2.互斥锁/互斥量(mutex)
3.自旋锁(spinlock_t)
4.原子操作(原子位/原子数)
5.完成量

信号量:
当线程尝试获取信号量而不得的时候,线程睡眠,CPU会重新调度.主要用于线程的同步,侧重与保持线程的同步有序.(同步是在互斥的基础上,实现有序,同步已经包含互斥),信号量可以由一个线程释放,另一个线程得到.
初始化:sema_init(&sem,val)
取得信号量:down_interruptible()//获取不到信号后的睡眠可被打断.
down_killable()
down_trylock()//以非阻塞的方式尝试获取信号量,物理是否获取都回返回.
down_timeout()//睡眠超时返回
down();
释放信号量:up()
sema_init初始化时,可以把val定义为大于1的值,这样多个线程可以同时获取该锁(相当于一把锁,有多个钥匙),当初始值为1时,其作用相当于互斥锁锁.

互斥量/ 互斥锁:
互斥量和信号量一样,当获取不到的时候,进程睡眠,CPU重新调度…主要用于线程的互斥同步,强调的是相互排斥,具有唯一性和排他性.二元性.但是互斥无法限制资源访问的顺序.
互斥量的加锁和解锁,必须由同一个线程使用(大多情况下,是在内核的某个可休眠函数的头和尾实现加解锁)
初始化:mutex_init()
获取:mutex_lock()
mutex_lock_interruptible()//
mutex_trylock()
释放:mutex_unlock()

自旋锁:
自旋锁,是忙等锁,不会睡眠,有CPU开销,获取不到锁的时候,回轮询等待.
初始化:spin_lock_init
获取: spin_lock
spin_trylock
spin_lock_irq//关闭本地中断.
spin_lock_irqsave //进入临界区时,关闭中断.退出临界区时,开中断,回恢复之前的中断状态.
释放:spin_unlock
spin_unlock_irqrestore//
spin_lock多用于不能睡眠的互斥代码中(比如中断).
spin_lock_irqsave()保存本地irq状态,并关闭.可用于实现进程与中断共享资源的情况:比如open/read中要读取的资源,同样在中断函数中也可能被修改.因为中断是第一优先级,因此当进程read共享资源的时候,可能被中断打断.因此标准调用中需要考虑这个因素,实现方式:在read/open等中调用spin_lock_irqsave /spin_unlock_irqrestore,在中断函数中调用spin_lock/spin_unlock

原子操作:
原子操作就是操作过程中不能被中断的过程,在被进行的过程中,可以确保CPU绝对不会再进行其他的针对该值的操作,原子操作仅回由一个CPU指令代表和完成,原子操作是无锁的,常常是直接通过CPU汇编指令实现.
其他的同步技术实现常常依赖于原子操作.
初始化:static atomic_t atomic_value = ATOMIC_INIT(0);
加减: atomic_set(&atomic_value ,1);
atomic_read(&atomic_value )
atomic_inc()
atomic_dec()

那么,貌似原子操作和spin_lock可以实现相同的互斥功能,那么他们有什么区别呢?分别用于什么情形中呢?
1.互斥锁是一种数据结构,用来让线程执行程序中的若干条关键的含有共享数据的代码.存在一定的性能消耗.互斥锁趋于悲观,用于假定被操作数会被其他代码修改.
2.原子操作针对的是单个值,粒度更小,CPU级的单挑指令实现.区域乐观:也就是说,假定该变量不会频繁被其他代码修改.当多次操作修改该值的时候,可能会失败.

完成量:
完成量和互斥量/互斥锁一样,是一种同步机制,用于在两个进程之间起同步作用:
而同步,强调的是有序的互斥.完成量强调的是两个进程之间的同步.信号量可以实现多个进程之间的有序.
当A进程调用wait_for_completion(&data->prev_finished),等待其他进程对置位data->prev_finished,执行complete操作.
B进程调用complete(&data->prev_finished),通知等待在在data->prev_finished的A进程,唤醒A并且使其继续运行.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九月天-深圳专业软硬件开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值