接上一篇,同步互斥方式 --- 有名信号量和无名信号量

四、同步互斥方式   ---  有名信号量
1、同步互斥的方式有哪些?
1)信号量         ---   进程
2)有名信号量     ---   进程
3)无名信号量     ---   线程
4)互斥锁         ---   线程
5)读写锁         ---   线程

2、什么是同步互斥?为什么要进行同步互斥?
同步互斥就是为了解决进程/线程在处理任务时有先后顺序,为了防止多个线程同时去抢占同一个资源。

3、有名信号量函数接口?
1)创建并打开一个有名信号量?   -->   sem_open()   --> man 3 sem_open
功能: initialize and open a named semaphore
    //初始化并且打开一个有名信号量

使用格式:
    #include <fcntl.h>          
        #include <sys/stat.h>        
        #include <semaphore.h>

       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:有名信号量的名字,要求必须以"/"开头,例如"/sem_test"     --> 最终这个文件会在/dev/shm/下目录创建
                          /xxxx  ->  在/dev/shm出现 sem.xxxx
    oflag:O_CREAT  --> 不存在则创建
            --> 存在就会忽略
    mode:八进制权限,例如:0777
    value:有名信号量的起始值

返回值:
    成功:有名信号量的地址  sem_t *
    失败:SEM_FAILED

2)有名信号量的p操作?   -->  sem_wait()   --> man 3 sem_wait
p操作: 资源数-1操作
    
   #include <semaphore.h>

  int sem_wait(sem_t *sem);

参数:
    sem:有名信号量的地址

返回值:
    成功:0
    失败:-1

如果当前的值为2,那么sem_wait()就会马上返回,并且将值设置为1。
如果当前的值为1,那么sem_wait()就会马上返回,并且将值设置为0。
如果当前的值为0,那么sem_wait()就会阻塞。


3)有名信号量的v操作?  --> sem_post()   --> man 3 sem_post

   #include <semaphore.h>

   int sem_post(sem_t *sem);

参数:
    sem:有名信号量的地址

返回值:
    成功:0
    失败:-1

如果当前的值为0,那么sem_post()就会马上返回,并且设置为1。
如果当前的值为1,那么sem_post()就会马上返回,并且设置为2。
如果当前的值为2,那么sem_post()就会马上返回,并且设置为3。


4)如何关闭有名信号量?   -->  sem_close()   --> man 3 sem_close

    #include <semaphore.h>

  int sem_close(sem_t *sem);

参数:
    sem:有名信号量的地址

返回值:
    成功:0
    失败:-1

5)如何删除有名信号量?   -->  sem_unlink()   --> man 3 sem_unlink

   #include <semaphore.h>

  int sem_unlink(const char *name);

参数:
    name:有名信号量的名字

返回值:
    成功:0
    失败:-1
    

    例题: 已知shm/目录下的代码会出现数据践踏,那么现在请让你把有名信号量添加到该代码中,解决数据践踏的问题。


写端:
#include <sys/shm.h>
#include <string.h>
#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>          
#include <sys/stat.h>

int main(int argc,char *argv[])
{
    //1. 申请key值
    key_t key = ftok(".",10);
    
    //2. 根据key值去申请共享内存的ID号
    int shmid = shmget(key,1024,IPC_CREAT|0666);
    
    //3. 根据ID号去共享内存中申请空间
    char *p = shmat(shmid,NULL,0);
    if(p == (void *)-1)
        printf("shmat error!\n");
    
    //3.5 创建并打开一个有名信号量
    sem_t *sem = NULL;
    sem = sem_open("/sem_test",O_CREAT,0777,0);
    if(sem == SEM_FAILED)
        printf("sem_open error!\n");
    
    //4. 不断往共享内存中写入数据
    while(1)
    {
        //开车进去
        fgets(p,1024,stdin);
        
        //车的数量自动加+1
        sem_post(sem);
        
        if(strncmp(p,"quit",4) == 0)
        {
            break;
        }
    }
    
    return 0;    
}

读端:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h>          
#include <sys/stat.h>

int main(int argc,char *argv[])
{
    //1. 申请key值
    key_t key = ftok(".",10);
    
    //2. 根据key值去申请共享内存的ID号
    int shmid = shmget(key,1024,IPC_CREAT|0666);
    
    //3. 根据ID号去共享内存中申请空间
    char *p = shmat(shmid,NULL,0);
    if(p == (void *)-1)
        printf("shmat error!\n");
    
    //3.5 创建并打开一个有名信号量
    sem_t *sem = NULL;
    sem = sem_open("/sem_test",O_CREAT,0777,0);
    if(sem == SEM_FAILED)
        printf("sem_open error!\n");
    
    //4. 每隔2秒就打印一次
    while(1)
    {
        //请问车的数量能不能减1?
        sem_wait(sem);
        
        printf("from shm:%s",p);
        
        if(strncmp(p,"quit",4) == 0)
        {
            break;
        }
    }
    
    //5. 撤销映射
    shmdt(p);
    
    //6. 删除共享内存IPC对象
    shmctl(shmid,IPC_RMID,NULL);
    
    //7. 关闭有名信号量
    sem_close(sem);
    
    //8. 删除有名信号量
    sem_unlink("/sem_test");

    return 0;
}


五、同步互斥方式   ---  无名信号量
1、无名信号量作用机制?
无名信号量不是一个文件,而是一个变量,所以无名信号量只能作用于同一个文件中,所以作用范围是线程之间。
机制:当某一个线程能抢占无名信号量的资源时,就可以访问公共资源。
      如果抢占不到,就只能阻塞等待。

2、关于无名信号量的函数接口。
由于无名信号量只是一个变量,不是一个文件,所以不能打开,只能初始化。

1)定义一个无名信号量的变量。   --> 数据类型: sem_t
   sem_t sem;

2)如何初始化无名信号量?   -->  sem_init()   -->  man 3 sem_init

功能: initialize an unnamed semaphore
    //初始化一个无名信号量

使用格式:
    #include <semaphore.h>

       int sem_init(sem_t *sem, int pshared, unsigned int value);

参数:
    sem:  无名信号量的地址
    pshared:  0  --> 线程之间
        非0  --> 亲缘关系进程之间
    value: 无名信号量的起始值

返回值:
    成功:0
    失败:-1
  

2)有名信号量的p操作?   -->  sem_wait()   --> man 3 sem_wait
p操作: 资源数-1操作
    
   #include <semaphore.h>

  int sem_wait(sem_t *sem);

参数:
    sem:有名信号量的地址

返回值:
    成功:0
    失败:-1

如果当前的值为2,那么sem_wait()就会马上返回,并且将值设置为1。
如果当前的值为1,那么sem_wait()就会马上返回,并且将值设置为0。
如果当前的值为0,那么sem_wait()就会阻塞。


3)有名信号量的v操作?  --> sem_post()   --> man 3 sem_post

   #include <semaphore.h>

   int sem_post(sem_t *sem);

参数:
    sem:有名信号量的地址

返回值:
    成功:0
    失败:-1

如果当前的值为0,那么sem_post()就会马上返回,并且设置为1。
如果当前的值为1,那么sem_post()就会马上返回,并且设置为2。
如果当前的值为2,那么sem_post()就会马上返回,并且设置为3。

4)如何销毁无名信号量?  --> sem_destroy()  --> man 3 sem_destroy

   #include <semaphore.h>

  int sem_destroy(sem_t *sem);

参数:
    sem: 无名信号量的地址

返回值:
    成功:0
    失败:-1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

肖爱Kun

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

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

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

打赏作者

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

抵扣说明:

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

余额充值