信号量编程简要实现

参考原文链接:https://blog.csdn.net/baidu_38621657/article/details/105724822
信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

1.特点
1.信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
2.信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
3每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
4.支持信号量组。
2.原型及相关API
最简单的信号量是只能取 0 和 1 的变量,这也是信号量最常见的一种形式,叫做二值信号量(Binary Semaphore)。而可以取多个正整数的信号量被称为通用信号量。

Linux 下的信号量函数都是在通用的信号量数组上进行操作,而不是在一个单一的二值信号量上进行操作。


1 #include <sys/sem.h>
2 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
3 int semget(key_t key, int num_sems, int sem_flags);
4 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5 int semop(int semid, struct sembuf semoparray[], size_t numops);  
6 // 控制信号量的相关信息
7 int semctl(int semid, int sem_num, int cmd, ...);

3.整个代码实现过程:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

union semun
{
        int val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short *array;  /* Array for GETALL, SETALL */
        struct seminfo *__buf;  /* Buffer for IPC_INFO(Linux-specific) */
};

void pGetkey(int id)
{
        //int semop(int semid, struct sembuf *sops, size_t nsops);
        struct sembuf set;
        set.sem_num = 0;
        set.sem_op = -1;
        set.sem_flg = SEM_UNDO;
        semop(id, &set, 1);
        printf("get the key\n");
}

void vPutBackkey(int id)
{
        struct sembuf set;
        set.sem_num = 0;
        set.sem_op = 1;
        set.sem_flg = SEM_UNDO;
        semop(id, &set, 1);
        printf("put back the key\n");
}

int main(int argc, char *argv[])
{
        //int semget(key_t key, int nsems, int semflg);
        int semid;
        int pid;
        key_t key;
        key = ftok(".", 5);
        if (key == -1){
                printf("get the key failuer!\n");
        }
                          //1代表信号量集合中有一个信号量,引用现有的一个信号量集合,取0                
        semid = semget(key, 1, IPC_CREAT | 0666);  //创建获取信号量
        if (semid == -1){
                printf("not get semid!\n");
                exit(-1);
        }

        //int semctl(int semid, int semnum, int cmd, ...),semctl()有3或4个参数,有4个参数时必须要使用来联合体
        union semun initsem;
        initsem.val = 0;  //将锁的数量设为一  
                    //操作第0个信号量
        semctl(semid, 0, SETVAL, initsem);  //初始化信号量
                       //SETVAL设置信号量的值,设为initsem  

        pid = fork();
        if (pid > 0){
                pGetkey(semid);  //去拿锁,注意对于父进程而言,拿锁必须得在printf之前,否则无法实现子进程比父进程先运行
                printf("this is the parent process\n");
                vPutBackkey(semid);  //去放锁
                semctl(semid, 0, IPC_RMID);  //销毁锁
        }
        else if (pid == 0){
                printf("this is the child process\n");
                vPutBackkey(semid); //因为在设置信号量状态时将锁的个数设为0,所以先调用子进程去放锁,然后父进程就回去拿锁最后再放锁
        }
        else {
                printf("fork failuer!\n");
        }

        return 0;
}

在拿锁放锁操作过程中会用到semop()函数,其中涉及到对结构体struct sembuf xxx进行赋值设置,semctl()设置4个参数时,是可以对信号量进行初始化设置的,第三个参数通常为SETVAL,第四个参数会用到联合体union semun xxx里的变量,比如int val(锁的数量);semctl()设置3个参数会对放回的锁进行销毁,避免造成内存资源的浪费。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对您的问题,我来简要介绍一下读者与写者问题的解决方案。 读者与写者问题是指多个进程同时访问同一共享资源的问题。在这个问题中,读者进程只读取共享资源,而写者进程则可以修改共享资源。如果多个进程同时对共享资源进行读写,就可能会出现数据不一致的问题。 为了防止这种情况的发生,我们需要对读者与写者进行同步。其中最常用的解决方案是使用信号量。 下面是使用信号量实现读者与写者同步的C语言代码: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #define READERS_NUM 5 #define WRITERS_NUM 2 sem_t mutex, write_mutex; int readers_count = 0; void *reader(void *arg) { int id = *(int *)arg; while (1) { sem_wait(&mutex); readers_count++; if (readers_count == 1) { sem_wait(&write_mutex); } sem_post(&mutex); printf("Reader %d is reading...\n", id); sem_wait(&mutex); readers_count--; if (readers_count == 0) { sem_post(&write_mutex); } sem_post(&mutex); } pthread_exit(NULL); } void *writer(void *arg) { int id = *(int *)arg; while (1) { sem_wait(&write_mutex); printf("Writer %d is writing...\n", id); sem_post(&write_mutex); } pthread_exit(NULL); } int main() { pthread_t readers[READERS_NUM], writers[WRITERS_NUM]; int i, reader_id[READERS_NUM], writer_id[WRITERS_NUM]; sem_init(&mutex, 0, 1); sem_init(&write_mutex, 0, 1); for (i = 0; i < READERS_NUM; i++) { reader_id[i] = i + 1; pthread_create(&readers[i], NULL, reader, &reader_id[i]); } for (i = 0; i < WRITERS_NUM; i++) { writer_id[i] = i + 1; pthread_create(&writers[i], NULL, writer, &writer_id[i]); } for (i = 0; i < READERS_NUM; i++) { pthread_join(readers[i], NULL); } for (i = 0; i < WRITERS_NUM; i++) { pthread_join(writers[i], NULL); } sem_destroy(&mutex); sem_destroy(&write_mutex); return 0; } ``` 在这段代码中,我们使用了两个信号量 `mutex` 和 `write_mutex`。`mutex` 用来互斥读者之间的访问,`write_mutex` 用来互斥写者之间的访问。同时,我们使用了一个整型变量 `readers_count` 来记录当前正在进行读操作的读者数量。 在读者进程中,我们首先使用 `sem_wait(&mutex)` 互斥读者之间的访问,然后将 `readers_count` 加 1,如果这个读者是第一个读者,则使用 `sem_wait(&write_mutex)` 阻塞写者进程,直到所有读者读取完成。读者读取完成后,再将 `readers_count` 减 1,如果当前没有读者正在读取,则使用 `sem_post(&write_mutex)` 唤醒写者进程。 在写者进程中,我们首先使用 `sem_wait(&write_mutex)` 等待互斥访问,然后进行写操作,最后使用 `sem_post(&write_mutex)` 释放写锁。 在 `main` 函数中,我们创建了多个读者和写者线程,并使用 `pthread_join` 等待它们的完成。最后,我们使用 `sem_destroy` 销毁信号量。 这样,我们就成功地使用信号量解决了读者与写者问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值