IPC/sem.c
kernel中include/uapi/linux/sem.h
/* semop system calls takes an array of these. */
struct sembuf {
unsigned short sem_num; /* semaphore index in array */要操作的信号灯的编号
short sem_op; /* semaphore operation */ 0 ---- 等待 +1 V操作 释放资源 -1 P操作
short sem_flg; /* operation flags */ 0,IPC_NOWAIT,SEM_UNDO
//SEM_UNDO 自动平衡信号量(因进程异常推出后系统给这个进程所加的锁给以释放(或者反向))
};
include/uapi/linux/sem.h
/* arg for semctl system calls. */
union semun {
int val; /* value for SETVAL */
struct semid_ds __user *buf; /* buffer for IPC_STAT & IPC_SET */
unsigned short __user *array; /* array for GETALL & SETALL */
struct seminfo __user *__buf; /* buffer for IPC_INFO */
void __user *__pad;
};
//////////////////////////////////////////////////////////////
pre.ctl { font-family: "Liberation Mono",monospace; }p { margin-bottom: 0.25cm; line-height: 120%; }
#include "sem_comm.h"
/* 封装 信号量的操作函数*/
/* 信号量的初始化 */
int init_sem(int semid, int semnum, int init_val)
{
union semun sun;
sun.val = init_val;
return semctl(semid, semnum, SETVAL, sun);
}
/*信号量的删除 */
int del_sem(int semid)
{
return semctl(semid, 0, IPC_RMID,0);
}
/*信号量的P操作 */
int sem_p(int semid, int sem_num, unsigned int nsops)
{
struct sembuf sbuf;
sbuf.sem_num = sem_num;
sbuf.sem_op = -1;
sbuf.sem_flg = SEM_UNDO;
return semop(semid, &sbuf, nsops);
}
/*信号量的V操作 */
int sem_v(int semid, int sem_num, unsigned int nsops)
{
struct sembuf sbuf;
sbuf.sem_num = sem_num;
sbuf.sem_op = 1;
sbuf.sem_flg = SEM_UNDO;
return semop(semid, &sbuf, nsops);
}
/*信号量的非阻塞P操作 */
int sem_try_p(int semid, int sem_num, unsigned int nsops)
{
struct sembuf sbuf;
sbuf.sem_num = sem_num;
sbuf.sem_op = -1;
sbuf.sem_flg = IPC_NOWAIT|SEM_UNDO;
return semop(semid, &sbuf, nsops);
}
/////////////////////////////////////////////////////////
shm_write.c
#include
#include
#include
#include
#include
#include
#include
#include "sem_comm.h"
#define SHM_KEY_PATH "."
#define SHM_KEY_ID 'a'
#define SEM_KEY_PATH "."
#define SEM_KEY_PRJ_ID 'b'
#define SHM_SIZE 2048
#define QUIT_STR "quit"
#define SEM_R 0
#define SEM_W 1
int main(void)
{
int shm_id = -1, sem_id = -1;
char *pShm = NULL;
/* 1. 创建共享内存和信号量*/
if((shm_id = shmget(ftok(SHM_KEY_PATH, SHM_KEY_ID), SHM_SIZE, IPC_CREAT|0666)) < 0) {
perror("shmget");
exit(1);
}
if( (sem_id = semget(ftok(SEM_KEY_PATH, SEM_KEY_PRJ_ID), 2, IPC_CREAT|0666)) < 0 ) {
perror("semget");
exit(1);
}
/*2. 映射共享内存和初始化信号量 */
if((pShm = shmat(shm_id, NULL, 0)) == (void *)-1) {
perror("shmat");
exit(1);
}
/*信号量初始化成写可用,读不可用*/
init_sem(sem_id, SEM_R, 0);
init_sem(sem_id, SEM_W, 1);
/* 3. 从标准键盘上获取用户的输入,写入到共享内存*/
char buf[BUFSIZ];
while(1) {
fprintf(stderr, "Please input string: ");
bzero(buf, BUFSIZ);
if( fgets(buf, BUFSIZ-1,stdin) == NULL) {
perror("fgets");
continue;
}
buf[BUFSIZ-1] = '\0'; /* 防止数组下标越界*/
int len = strlen(buf);
sem_p(sem_id, SEM_W, 1); //Psem_w操作
bzero(pShm,SHM_SIZE);
/* 加入一个len是为了防止数组下标越界*/
if(len > SHM_SIZE -1) {
len = SHM_SIZE -1;
}
strncpy(pShm, buf, len);
if(!strncasecmp(pShm, QUIT_STR, strlen(QUIT_STR))) { //用户输入了"quit"
sem_v(sem_id, SEM_R, 1); //Vsem_r操作
break;
}
sem_v(sem_id, SEM_R, 1); //Vsem_r操作
}
/*4. 撤销映射*/
shmdt(pShm);
pShm = NULL;
/*5.删除共享内存*/
// shmctl(shm_id, IPC_RMID, NULL);
return 0;
};
/////////////////////////////////////////
shm_reader.c
#include
#include
#include
#include
#include
#include
#include
#include "sem_comm.h"
#define SHM_KEY_PATH "."
#define SHM_KEY_ID 'a'
#define SEM_KEY_PATH "."
#define SEM_KEY_PRJ_ID 'b'
/*在内核中的信号量数组的下标 */
#define SEM_R 0
#define SEM_W 1
#define SHM_SIZE 2048
#define QUIT_STR "quit"
int main(void)
{
int shm_id = -1, sem_id = -1;
char *pShm = NULL;
/* 1. 打开共享内存和信号量*/
if((shm_id = shmget(ftok(SHM_KEY_PATH, SHM_KEY_ID), SHM_SIZE, IPC_CREAT|0666)) < 0) {
perror("shmget");
exit(1);
}
//注意semget获取两个信号量的用法
//见IPC/sem.c SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg) 查看semget这个系统调用的实现
if( (sem_id = semget(ftok(SEM_KEY_PATH, SEM_KEY_PRJ_ID), 2, IPC_CREAT|0666)) < 0 ) {
perror("semget");
exit(1);
}
/*2. 映射共享内存 */
if((pShm = shmat(shm_id, NULL, 0)) == (void *)-1) {
perror("shmat");
exit(1);
}
/*3. 读共享内存 */
while(1) {
sem_p(sem_id, SEM_R, 1); //Psem_r操作
if(strlen(pShm)) {
printf("Reader: %s\n", pShm);
if(!strncasecmp(pShm, QUIT_STR, strlen(QUIT_STR))) { //用户输入了"quit"
sem_v(sem_id, SEM_W, 1); //Vsem_w操作
break;
}
bzero(pShm, BUFSIZ);
}
sem_v(sem_id, SEM_W, 1); //Vsem_w操作
}
/*4. 撤销映射*/
shmdt(pShm);
pShm = NULL;
/*5.删除共享内存和信号量*/
shmctl(shm_id, IPC_RMID, NULL);
del_sem(sem_id);
return 0;
};
//////////////////////////////////////////////////////////////////////////////////
阅读(1247) | 评论(0) | 转发(0) |