进程间同步

进程同步

_sync 原子操作

  • type __sync_fetch_and_add (type *ptr, type value, ...): 将value加到ptr上,结果更新到ptr,并返回操作之前*ptr的值
  • type __sync_fetch_and_sub (type *ptr, type value, ...):从ptr减去value,结果更新到ptr,并返回操作之前*ptr的值
  • type __sync_fetch_and_or (type *ptr, type value, ...): 将ptr与value相或,结果更新到ptr, 并返回操作之前*ptr的值
  • type __sync_fetch_and_and (type *ptr, type value, ...): 将ptr与value相与,结果更新到ptr,并返回操作之前ptr的值
    +type __sync_fetch_and_xor (type *ptr, type value, ...):将
    ptr与value异或,结果更新到ptr,并返回操作之前ptr的值
  • type __sync_fetch_and_nand (type *ptr, type value, ...): 将ptr取反后,与value相与,结果更新到ptr,并返回操作之前ptr的值
    +type __sync_add_and_fetch (type *ptr, type value, ...):将value加到
    ptr上,结果更新到ptr,并返回操作之后新ptr的值
  • type __sync_sub_and_fetch (type *ptr, type value, ...):从ptr减去value,结果更新到ptr,并返回操作之后新*ptr的值
  • type __sync_or_and_fetch (type *ptr, type value, ...):将ptr与value相或, 结果更新到ptr,并返回操作之后新*ptr的值
  • type __sync_and_and_fetch (type *ptr, type value, ...):将ptr与value相与,结果更新到ptr,并返回操作之后新*ptr的值
  • type __sync_xor_and_fetch (type *ptr, type value, ...):将ptr与value异或,结果更新到ptr,并返回操作之后新ptr的值
    +type __sync_nand_and_fetch (type *ptr, type value, ...):将
    ptr取反后,与value相与,结果更新到ptr,并返回操作之后新ptr的值
  • bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...):比较*ptr与oldval的值,如果两者相等,则将newval更新到*ptr并返回true
  • type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...):比较ptr与oldval的值,如果两者相等,则将newval更新到ptr并返回操作之前*ptr的值
  • __sync_synchronize (...):发出完整内存栅栏
    +type __sync_lock_test_and_set (type *ptr, type value, ...): 将value写入ptr,对ptr加锁,并返回操作之前*ptr的值。即,try spinlock语义
  • void __sync_lock_release (type *ptr, ...):将0写入到ptr,并对ptr解锁。即,unlock spinlock语义
18-1-syn-fetch-1.c

原理解释

对比 __sync_fetch_and_add()__sync_add_and_fetch()函数的区别
__sync_fetch_and_add()是先将数据取出来再进行加法操作。
__sync_add_and_fetch()是先进加法操作再将数据取出来

细节解释
运行结果:
在这里插入图片描述
先将数据取出来的话,i=10,这时直接打印出来得到ret=10,再进行加法操作。类似于i++
先进行加法操作得:i=30,这时候打印出来得到ret = 30。类似于++i

18-1-syn-fetch-2.c

原理解释

创建40个子线程对全局变量count进行递增操作,由于是多线程对同一个变量进行操作,所以需要做到同步互斥。
使用__sync_fetch_and_add()函数来完成递增操作。

原子操作__sync_fetch_and_add()可使得一次只有一个线程能对同一个共享数据进行操作,因此该函数可以做到多线程同步。

细节解释
运行结果:
在这里插入图片描述

18-1-syn-fetch-3.c

原理解释

本程序是18-1-syn-fetch-2.c的一个对比程序,即不使用原子操作__sync_fetch_and_add(),直接使用count++来完成多线程递增操作。
count++会导致一次有多个线程同时对count变量进行操作,最后会导致count变量的值远小于期望值。

细节解释
运行结果:
在这里插入图片描述

18-2-syn-compare-test.c

原理解释

验证 bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)函数,type __sync_lock_test_and_set (type *ptr, type value, ...)void __sync_lock_release (type *ptr, ...)函数

细节解释

  • bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...):比较*ptr与oldval的值,如果两者相等,则将newval更新到*ptr并返回true
  • type __sync_lock_test_and_set (type *ptr, type value, ...): 将value写入*ptr,对*ptr加锁,并返回操作之前*ptr的值。
  • void __sync_lock_release (type *ptr, ...):将0写入到*ptr,并对*ptr解锁。

在这里插入图片描述
在这里插入图片描述

运行结果:
在这里插入图片描述

互斥锁

Linux提供互斥锁来保护内核中的关键部分。
任务在进入临界区之前调用mutex_lock()函数,并在退出临界区之后调用mutex_unlock()函数。
如果互斥锁资源被占用,则调用mutex_lock()的任务将会进入睡眠状态,在等待队列中等待,并在互斥锁资源的拥有者调用mutex_unlock()时被唤醒。

POSIX所提供的互斥解决方法包括:
  • mutex locks
  • semaphores
  • condition variables
  • Non-portable extensions indlude:
    • read-wirte
    • spinlocks
18-3-syn-pthread-mutex.c

原理解释
两个函数做对比,一个使用了互斥锁,一个没有

细节解释
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

POSIX信号量

POSIX信号量有两种:有名信号量和无名信号量,无名信号量也被称作基于内存的信号量。有名信号量通过IPC名字进行进程间的同步,而无名信号量如果不是放在进程间的共享内存区中,是不能用来进行进程间同步的,只能用来进行线程同步。(类比管道)

有名信号量

sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
函数功能:创建或打开一个信号量
参数:

  • name 信号量的名字,标识信号量
  • oflag oflag参数可以为:0,O_CREAT,O_EXCL。如果为0表示打开一个已存在的信号量,如果为O_CREAT,表示如果信号量不存在就创建一个信号量,如果存在则打开被返回。此时mode和value需要指定。如果为O_CREAT | O_EXCL,表示如果信号量已存在会返回错误。
  • mode 权限位
  • value 信号量的初始值
    返回值:信号量指针,该指针可供其他对该信号量进行操作的函数使用

int sem_wait(sem_t *sem);
函数功能:将信号量的值减1。如果信号量=0,则sem_wait会阻塞,直到成功使信号量减1

int sem_post(sem_t *sem);
函数功能:将信号量的值加1,也就是释放信号量

int sem_close(sem_t *sem)
函数功能:关闭有名信号量

无名信号量

int sem_init(sem_t *sem, int pshared,unsigned value);
函数功能:初始化指定的信号量
参数:

  • sem:信号量变量名
  • value:信号量的初始值
  • shared:参数pshared用于说明信号量的共享范围,如果pshared为0,那么该信号量只能由初始化这个信号量的进程中的线程使用,如果pshared非零,任何可以访问到这个信号量的进程都可以使用这个信号量。
    返回值:
  • 成功返回0
  • 失败返回错误号

int sem_destroy(sem_t *sem);
函数功能:销毁一个信号量
参数:

  • sem:信号量变量名
    返回值:
  • 成功返回0
  • 失败返回错误号
    int sem_wait(sem_t *sem);
    函数功能:将信号量的值减1。如果信号量=0,则sem_wait会阻塞,直到成功使信号量减1

int sem_post(sem_t *sem);
函数功能:将信号量的值加1,也就是释放信号量

18-4-syn-pthread-sem-unamed.c

原理解释

程序大致实现思路与18-3程序相似,只是将同步实现的方式换成无名信号量来实现。

细节解释
在这里插入图片描述
在这里插入图片描述
运行结果:在这里插入图片描述

18-5-syn-pthread-sem-unamed.c

原理解释

程序大致实现思路与18-3程序相似,只是将同步实现的方式换成有名信号量来实现

细节解释
在这里插入图片描述

18-6-syn-pc-con.c

原理解释

这是一个生产者-消费者问题,并且生产者和消费者都是多个的。
生产者将生产好的item放在循环队列中,消费者从循环队列中取出item。
在这里必须做到同步,我们对要生产的item进行编号,一个item只能由一个生产者生产,也只能被一个消费者取走。
实现方法:我们先申请一块共享内存区域,该区域内有一个循环队列,enqueue指向队头,dequeue指向队尾。同时,我们需要记录已经生产了多少item和消费了多少item。当生产的item数量达到要求所有生产者就停止生产,当消费者取出的item达到要求时也退出。

细节解释

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

18-7-syn-pc-producer.c

原理解释
在生产者进程中创建多个子线程来互斥的完成生产工作。使用信号量来完成互斥工作。
细节解释
在这里插入图片描述
在这里插入图片描述

18-8-syn-pc-consumer.c

在这里插入图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值