高端广告公司网站建设,购物网站建设计划书,福州网站建站建设,线下推广活动策划方案一、信号量的定义和原理
1、概念 原子操作#xff1a;不可中断的一个或者一系列的操作#xff0c;即一件事要么做要么不做。临界资源#xff1a;不同进程能够看到的一份公共资源#xff0c;一次只能被一个进程使用。PV操作#xff1a;由于信号量只能进行两种操作等待和发…一、信号量的定义和原理
1、概念 原子操作不可中断的一个或者一系列的操作即一件事要么做要么不做。临界资源不同进程能够看到的一份公共资源一次只能被一个进程使用。PV操作由于信号量只能进行两种操作等待和发送信号即P(sv)和V(sv),他们的行为是这样的 P(sv)如果sv的值大于零就给它减1如果它的值为零就挂起该进程的执行 V(sv)如果有其他进程因等待sv而被挂起就让它恢复运行如果没有进程因等待sv而挂起就给它加1。 就是两个进程共享信号量sv一旦其中一个进程执行了P(sv)操作它将得到信号量并可以进入临界区使sv减1。而第二个进程将被阻止进入临界区因为当它试图执行P(sv)时sv为0它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量这时第二个进程就可以恢复执行。 2、信号量的定义 为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题我们需要一种方法它可以通过生成并使用令牌来授权在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制让一个临界区同一时间只有一个线程在访问它也就是说信号量是用来调协进程对共享资源的访问的。 3、信号量的原理 1. 测试控制该资源的信号量 2. 若信号量的值为正则进程可以使用该资源进程的信号量值减1表示一个资源被使用 3. 若此信号量为0则进程进入休眠直到该信号量值大于0 4. 当进程不再使用一个由一个信号控制的共享资源时该信号量加1如果有进程正在休眠等待该信号量则该进程会被唤醒。 二、信号量的使用
1、一些数据结构的定义
1semid_ds 内核为每个信号量集合维护着一个结构体
struct semid_ds{struct ipc_perm sem_perm;unsigned short sem_nsems;time_t sem_otime;time_t sem_ctime;...
}
2semun必须定义该联合体
union semun{int val;struct semid_ds *buf;unsigned short *array;
}
3sembuf信号量操作数组
struct sembuf{// 除非使用一组信号量否则它为0一般从0,1,...num_secs-1unsigned short sem_num; // 信号量在一次操作中需要改变的数据通常是两个数一个是-1// 即P等待操作一个是1即V发送信号操作。short sem_op;// 通常为SEM_UNDO,使操作系统跟踪信号// 并在进程没有释放该信号量而终止时操作系统释放信号量。short sem_flg;
}
2、semget函数
#include sys/sem.h
int semget(key_t key, int num_sems, int sem_flags); 功能创建一个新信号量集或取得一个已有信号量集。参数 key整数值唯一非零不相关的进程可以通过它访问一个信号量它代表程序可能要使用的某个资源程序对所有信号量的访问都是间接的程序先通过调用semget函数并提供一个键再由系统生成一个相应的信号标识符semget函数的返回值只有semget函数才直接使用信号量键所有其他的信号量函数使用由semget函数返回的信号量标识符。如果多个程序使用相同的key值key将负责协调工作 num_sems指定需要的信号量数目它的值几乎总是1 sem_flags一组标志当想要当信号量不存在时创建一个新的信号量可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后即使给出的键是一个已有信号量的键也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的唯一的信号量如果信号量已存在返回一个错误。 返回值成功返回一个相应信号标识符非零失败返回-1。 3、semop函数
#include sys/sem.h
int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops); 功能它的作用是改变信号量的值。参数 sem_id由semget返回的信号量标识符 sem_opa表示一个由sembuf结构表示的信号量操作数组 num_sem_ops规定该数组中操作的数量。返回值成功返回0失败返回-1。 4、semctl函数
#include sys/sem.h
int semctl(int sem_id, int sem_num, int command, ...); 功能直接控制信号量的信息。参数 sem_id信号量标识符 sem_num信号量的值 command通常是下面两个值中的其中一个 SETVAL用来把信号量初始化为一个已知的值。p 这个值通过union semun中的val成员设置其作用是在信号量第一次使用前对它进行设置 IPC_RMID用于删除一个已经无需继续使用的信号量标识符。返回值成功返回0失败返回-1。 三、信号量的demo
// comm.h
#ifndef _MYSEM_H_
#define _MYSEM_H_#include stdio.h
#include sys/types.h
#include sys/ipc.h // ftok
#include sys/sem.h
#include sys/wait.h
#include string.h#define PATHNAME . // ftok 中生成key值 . 表示当前路径
#define PROJ_ID 56 // ftok 中配合PATHNAME 生成唯一key值union semun
{int val;struct semid_ds *buf;unsigned short *array;struct seminfo *_buf;
};int create_sems(int nums); // 创建含有nums个信号量的集合
int get_sems(); // 获取信号量
// 初始化semid对应的信号量集中编号为which的信号量值为value
int init_sems(int semid , int which, int value);
int destroy_sems(int semid); // 释放该信号量集
int P(int semid, int which); // 表示分配 信号量值-1
int V(int semid, int which); // 表示释放 信号量值1#endif /* _MYSEM_H_ */
// comm.cpp
#include comm.h// 创建信号量和获取信号量公用函数
static int comm_sem(int nums , int semflag)
{// ftok 函数把一个已存在的路径名和一个整数标识转换成一个key_t值// 即IPC关键字。key_t key ftok(PATHNAME, PROJ_ID);if(key 0){perror(ftok);return -1;}// 用来创建一个信号集或者获取已存在的信号集。int semid semget(key, nums, semflag); if( semid 0){perror(semget);return -1;}return semid;
}// 初始化操作数组
static int comm_sem_op(int semid, int which, int op)
{struct sembuf _sembuf;_sembuf.sem_num which;_sembuf.sem_op op;_sembuf.sem_flg 0; // IPC_NOWAIT SEM_UNDOreturn semop(semid, _sembuf, 1);
}// 创建含有nums个信号量的集合
int create_sems(int nums)
{return comm_sem(nums, IPC_CREAT|IPC_EXCL|0666);
}// 初始化信号集
int init_sems(int semid , int which, int value)
{union semun _semun;_semun.val value;int ret semctl(semid, which, SETVAL,_semun);if(ret 0){perror(inin_sem);return -1;}return 0;
}// 获取信号量
int get_sems()
{return comm_sem(0, IPC_CREAT);
}// 释放该信号量集
int destroy_sems(int semid)
{int ret semctl(semid, 0, IPC_RMID, NULL);if(ret 0){perror(rm_sem);return -1;}return 0;
}// P操作
int P(int semid, int which)
{return comm_sem_op(semid, which , -1);
}// V操作
int V(int semid, int which)
{return comm_sem_op(semid, which, 1);
}
// test.cpp
#include comm.h
#include stdio.h
#include unistd.hint main()
{int semid create_sems(10); // 创建一个包含10个信号量的信号集init_sems(semid, 0, 1); // 初始化编号为 0 的信号量值为1pid_t id fork(); // 创建子进程if (id 0){perror(fork);return -1;}else if (0 id) // 子进程{ int sem_id get_sems();while(1){P(sem_id, 0); // 对该信号量集中的0号信号做P操作printf(你);fflush(stdout);sleep(1);printf(好);printf(:);fflush(stdout);sleep(1);V(sem_id, 0);}}else // 父进程{while(1){P(semid,0);printf(在);sleep(1);printf(吗);printf(?);fflush(stdout);V(semid, 0);}wait(NULL);}destroy_sems(semid);return 0;
}
四、信号量的总结 信号量是一个特殊的变量程序对其访问都是原子操作且只允许对它进行等待即P(信号变量))和发送即V(信号变量))信息操作。我们经常通过信号来解决多个进程对同一资源的访问竞争的问题使在任一时刻只能有一个执行线程访问代码的临界区域也可以说它是协调进程间的对同一资源的访问权也就是用于同步进程的。
【优点】可以同步进程。 【缺点】信号量有限。