利用信号量实现互斥访问资源:
#include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/sem.h> //本例描述互斥的打印字符AAZZ必须成对出现 union semun{ int val; }; int id; void print(char c) { int i = 5; struct sembuf sb[1]; sb[0].sem_num = 0; sb[0].sem_flg = 0; while(i--) { sb[0].sem_op = -1; //P操作 semop(id, sb, 1); printf("%c", c); //这里可以看做打印两个字符的操作是 fflush(stdout); //绑定在一起的,无论间隔多长时间 sleep(rand()%3); printf("%c", c); fflush(stdout); sb[0].sem_op = 1; //V操作 semop(id, sb, 1); sleep(rand()%2); } } int main() { srand(getpid()); id = semget(123, 1, IPC_CREAT|0644); if(-1 == id) perror("semget"), exit(1); union semun su = {1}; if(-1 == semctl(id, 0, SETVAL, su)) { perror("semctl"); exit(1); } pid_t pid = fork(); if(-1 == pid) { perror("fork"); exit(1); } else if(0 == pid) { print('A'); } else { print('Z'); } semctl(id, IPC_RMID, 0); return 0; }
信号量互斥和同步实现哲学家思考问题案例:
#include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/sem.h> //哲学家就餐问题 典型的死锁问题,本程序采用的方法是, //一个哲学家要么两个筷子都拿到,要么两只筷子都拿不到。 int id; union semun{ int value; }; void GetTwoChop(int no) { struct sembuf sb[2] = { {no, -1, 0}, {(no+1) % 5 , -1, 0} }; semop(id, sb, 2); } void PutTwoChop(int no) { struct sembuf sb[2] = { {no, 1, 0}, {(no+1) % 5 , 1, 0} }; semop(id, sb, 2); } void fun(int no) { while(1) { printf("第%d个哲学家开始思考!\n", no); sleep(rand()%2); GetTwoChop(no); printf("第%d个哲学家开始就餐!\n", no); sleep(rand()%5); printf("第%d个哲学家就餐结束!\n", no); PutTwoChop(no); } } int main() { srand(getpid()); //生成随机数种子 id = semget(123, 5, IPC_CREAT|0644); //有5个哲学家,即需要5个信号量 if(-1 == id) { perror("semget"); exit(1); } union semun su = {1}; int i = 0; int nu = 0; for(i = 0; i < 5; i++) { if (-1 == semctl(id, i, SETVAL, su))//初始化信号量;每根筷子有两种状态 // 0 和 1 { perror("semctl"); exit(1); } } for(i = 1 ; i < 5; i++ ) //创建5个进程,一个父进程,4个子进程 { if(0 == fork()) { nu = i; break; } } fun(nu); //每个哲学家有不同的nu,执行不同的操作 return 0; }
利用共享内存及信号量知识实现生产者消费者模型:
自定义头文件:
#ifndef __SHMFIFO_H__ #define __SHMFIFO_H__ typedef struct shm_head{ int rd_idx; //读出时的位置 int wr_idx; //写入时的位置 int blocks; //块的数量 int blksz; //块的大小 }head_t; typedef struct shmfifo{ head_t* p_head; //共享内存段的头的起始位置 char* p_payload; //有效数据的地址 int shmid; //共享内存id int sem_full; //共享内存满 int sem_empty; //表示还有几个空闲 int sem_mutex; //互斥量 }shmfifo_t; //共享内存段的初始化,需要的参数分别是共享内存段的打开时的 //起始key值, 块的数量, 每块的大小 shmfifo_t* shmfifo_init(int key, int blocks, int blksz); //生产者生产,即存放操作,需要的参数是共享队列的地址, //以及要存放的数据的地址,这里不考虑大小是因为我们默认的 //要存入的数据大小和块的大小是相等的 void shmfifo_put(shmfifo_t* fifo, const void* buf); //消费者消费, 即取出操作,原理同存入操作相同 void shmfifo_get(shmfifo_t* fifo, void* buf); //共享队列的销毁 void shmfifo_destroy(shmfifo_t* fifo); #endif // __SHMFIFO_H__
具体实现:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include <assert.h> #include <string.h> #include "shmfifo.h" union semun{ int value; }; static void p(int id) { struct sembuf sb[1]; sb[0].sem_num = 0; sb[0].sem_op = -1; sb[0].sem_flg = 0; semop(id, sb, 1); } static void v(int id) { struct sembuf sb[1]; sb[0].sem_num = 0; sb[0].sem_op = 1; sb[0].sem_flg = 0; semop(id, sb, 1); } shmfifo_t* shmfifo_init(int key, int blocks, int blksz) { shmfifo_t* p = (shmfifo_t*)malloc(sizeof(shmfifo_t)); if(NULL == p) { perror("malloc"); exit(1); } int len = blocks *blksz + sizeof(head_t); int shmid = shmget(key, len, 0); if(-1 == shmid){ //共享内存段不存在,创建 shmid = shmget(key, len, IPC_CREAT|0644); p->p_head = (head_t*)shmat(shmid, NULL, 0); p->p_head->rd_idx = 0; p->p_head->wr_idx = 0; p->p_head->blocks = blocks; p->p_head->blksz = blksz; p->p_payload = (char*)(p->p_head + 1); p->shmid = shmid; p->sem_full = semget(key, 1, IPC_CREAT|0644); p->sem_empty = semget(key + 1, 1, IPC_CREAT|0644); p->sem_mutex = semget(key + 2, 1, IPC_CREAT|0644); union semun su; su.value = blocks; semctl(p->sem_full, 0, SETVAL, su); su.value = 0; semctl(p->sem_empty, 0, SETVAL, su); su.value = 1; semctl(p->sem_mutex, 0, SETVAL, su); } else //已经存在,直接打开 { p->p_head = (head_t*)shmat(shmid, NULL, 0); p->p_payload = (char*)(p->p_head + 1); p->shmid = shmid; p->sem_full = semget(key, 0, 0); p->sem_empty = semget(key + 1, 0, 0); p->sem_mutex = semget(key + 2, 0, 0); } return p; } void shmfifo_put(shmfifo_t *fifo, const void* buf) { p(fifo->sem_full); //同步,共享队列中生产者生产,类似于判断共享队列是否满 p(fifo->sem_mutex); //互斥访问当前正在写入的资源 memcpy(fifo->p_payload + (fifo->p_head->wr_idx * fifo->p_head->blksz), buf, fifo->p_head->blksz); fifo->p_head->wr_idx = (fifo->p_head->wr_idx + 1) % fifo->p_head->blocks; v(fifo->sem_mutex); v(fifo->sem_empty); } void shmfifo_get(shmfifo_t *fifo, void* buf) { p(fifo->sem_empty); //同步 p(fifo->sem_mutex); //互斥 memcpy(buf, fifo->p_payload + (fifo->p_head->rd_idx * fifo->p_head->blksz), fifo->p_head->blksz); fifo->p_head->rd_idx = (fifo->p_head->rd_idx + 1) % fifo->p_head->blocks; v(fifo->sem_mutex); v(fifo->sem_full); } void shmfifo_destroy(shmfifo_t* fifo) { shmdt(fifo->p_head); shmctl(fifo->shmid, IPC_RMID, 0); shmctl(fifo->sem_full, 0, IPC_RMID); shmctl(fifo->sem_empty, 0, IPC_RMID); shmctl(fifo->sem_mutex, 0, IPC_RMID); free(fifo); fifo = NULL; }
存放操作:
#include <stdio.h> #include "shmfifo.h" typedef struct person{ char _name[32]; int _age; }person_t; int main() { shmfifo_t* fifo = shmfifo_init(123, 5, sizeof(person_t)); person_t person; int i = 0; for(; i < 10; i++) { person._age = 10 + i; sprintf(person._name, "name:%d", i+1); shmfifo_put(fifo,&person); printf("put %d\n", i+1); } return 0; }取出操作:
#include <stdio.h> #include "shmfifo.h" typedef struct person{ char _name[32]; int _age; }person_t; int main() { shmfifo_t* fifo = shmfifo_init(123, 5, sizeof(person_t)); person_t person; int i = 0; for(; i < 10; i++) { shmfifo_get(fifo, &person); printf("name = %s, age = %d \n", person._name, person._age); sleep(1); } shmfifo_destroy(fifo); return 0; }