利用信号量实现互斥访问资源:
#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;
}