Posix信号灯和SystemV信号灯解析
来源:互联网 发布:足球球员数据软件 编辑:程序博客网 时间:2024/05/17 09:44
暑假那会把UNPv2大概过了一遍,不过没有总结,除了pipe,所以现在都忘得差不多了,趁最近几天学操作系统,边学边回顾一下。
信号灯(semaphore)是一种用于提供不同进程间或一个给定进程的不同线程的同步手段的原语。
我所知一共有三种类型信号灯:
- Posix有名信号灯:使用Posix IPC名字标识,可用于进程或现程间的同步
- Posix基于内存的信号灯:存放在共享内存区,可用于进程或线程间的同步
- System V信号灯:在内核中维护,可用于进程或线程间的同步
下面给出信号灯、互斥锁、条件变量之间的三个差异:
- 互斥锁必须总是由给它上锁的线程解锁,信号灯则可以由其它线程解锁。
- 互斥锁要么被锁住,要么被解开(二值状态,类似于二值信号灯)
- 既然信号灯有一个与之关联的状态(它的计数值),信号灯挂出操作总是被记住。然而当向一个条件变量发送信号时,如果没有线程等待在该条件变量上,那么该信号将丢失(丢失就是好像没出现过这货一样)。
一:Posix有名信号灯
sem_t *sem_open(const char *name, int oflag);sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);name:打开信号灯,name是给信号灯起的名字,也就是信号灯对应在文件系统中的路径,加入你打开了一个信号灯,该信号灯是随内核持续的,就算你的程序结束了,信号灯 依然存在,ll /dev/shm即可看到。销毁信号灯需要程序中调用unlink函数(对于使用内存的信号灯而言是destroy函数)或者机器重启,调用close函数也不行。
int sem_close(sem_t *sem);这个函数虽说close,实际没什么乱用,即便不使用该函数,eixt或_exit的时候也会自动关闭信号灯。但是不能从系统中删除。失败返回-1。
int sem_unlink(const char* name);name:信号灯对应的文件系统名字。
int sem_wait(sem_t *sem);int sem_trywait(sem_t *sem);
int sem_post(sem_t *sem);与上面函数作用相反,加1函数。
int sem_getvalue(sem_t* sem, int *valp);使用Int*获得当前信号灯的值。
#include "../unp.h"#define NBUFF 10#define SEM_MUTEX "mutex" //thers are args to ipc name.#define SEM_NEMPTY "nempty"#define SEM_NSTORED "nstored"int nitems; //read-only by producer and consumerstruct { int buff_[NBUFF]; sem_t* mutex_; sem_t* nempty_; sem_t* nstored_;} shared;void *produce(void *), *consume(void *); int main(int argc, char** argv){ if(argc != 2) err_quit("usage: prodcons1 <#items>"); nitems = atoi(argv[1]); //create three semephore shared.mutex_ = sem_open(SEM_MUTEX, O_CREAT | O_EXCL, FILE_MODE, 1); //1 assert(shared.mutex_ != (sem_t*)(-1)); shared.nempty_ = sem_open(SEM_NEMPTY, O_CREAT | O_EXCL, FILE_MODE, NBUFF); //NBUFF assert(shared.nempty_ != (sem_t*)(-1)); shared.nstored_ = sem_open(SEM_NSTORED, O_CREAT | O_EXCL, FILE_MODE, 0); //0 assert(shared.nstored_ != (sem_t*)(-1)); //create one producer thread and one consumer thread int ret = 0; pthread_t tid_produce, tid_consume; ret = pthread_create(&tid_produce, NULL, produce, NULL); assert(ret != -1); ret = pthread_create(&tid_consume, NULL, consume, NULL); assert(ret != -1); //wait for the two threads pthread_join(tid_produce, NULL); pthread_join(tid_consume, NULL); sem_unlink(SEM_MUTEX); sem_unlink(SEM_NEMPTY); sem_unlink(SEM_NSTORED); exit(0);} void *produce(void *){ for(int i=0; i<nitems; ++i){ sem_wait(shared.nempty_); sem_wait(shared.mutex_); shared.buff_[i%NBUFF] = 1; printf("producer produce the %d=%d\n", i, shared.buff_[i]); sem_post(shared.mutex_); sem_post(shared.nstored_); }}void *consume(void *){ for(int i=0; i<nitems; ++i){ sem_wait(shared.mutex_); sem_wait(shared.nstored_); shared.buff_[i%NBUFF] = 0; printf("consumer consume the %d=%d\n", i, shared.buff_[i]); sem_post(shared.mutex_); sem_post(shared.nempty_); }}
二:Posix基于内存的信号灯
int sem_init(sem_t *sem, int shared, unsigned int value);初始化信号灯。sem参数必须指向有应用程序分配的sem_t变量。如果shared为0,那么待初始化的信号灯是在同一进程中的各个线程间共享的,否则该信号灯是在进程间共享的。当shared为非零时,该信号灯必须存放在即将使用它的所有进程都能访问的某种类型的共享内存中。value是初始值。
int sem_destroy(sem_t* sem);使用完一个基于内存的信号灯后,我们调用sem_destroy摧毁它。
- SEM_NSEMS_MAX 一个进程可同时打开着的最大信号灯数(Posix要求至少为256)
- SEM_VALUE_MAX 一个信号灯的最大值(Posix要求至少为32767)
三:System V信号灯
- 计数信号灯集(set of counting semaphore):一个或多个信号灯(构成一个集合),其中每个都是计算信号灯。每个集合的信号灯数存在一个限制,一般在25个数量级上。当我们谈论“System V信号灯”时,所指的是计数信号灯集。当我们谈论“Posix信号灯”时,所指的是单个计数信号灯。
struct semid_ds { struct ipc_permsem_perm ; structsem* sem_base ; //信号数组指针 ushort sem_nsem ; //此集中信号个数 time_t sem_otime ; //最后一次semop时间 time_t sem_ctime ; //最后一次创建时间} ;
struct sem { ushort_t semval ; //信号量的值 short sempid ; //最后一个调用semop的进程ID ushort semncnt ; //等待该信号量值大于当前值的进程数(一有进程释放资源 就被唤醒) ushort semzcnt ; //等待该信号量值等于0的进程数} ;
key_t ftok(char *pathname, char proj);
根据参数pathname和proj来创建一个关键字,成功时返回与路径pathname相对应的一个键值,具有唯一性,失败时返回值为-1.
int semget (key_t key, int nsems , int semflg);
创建一个新信号量或者取得一个现有的信号量,key是一个关键字,可以是用ftok()函数创建的,也可以是IPC_PRIVATE(/usr/include/bits$ vi ipc.h),nsems表明创建的信号量个数,semflg是设置信号量的访问权限标志,函数调用成功时返回信号量ID,失败则返回-1.
int semop (int semid, struct sembuf *spos, int nspos);
对信号量进行操作的函数,用于改变信号量的键值,semid是信号量的标志,spos是指向一个结构体数组的指针,表明要进行什么操作,nspos表明数组的元素个数,调用成功则返回0,失败则返回-1。/usr/include/linux$ vi sem.h (sembuf \ semun)
Struct sembuf
{
Unsigned short sem_num; /*sem index in array*/
Short sem_op; /* sem operation */
Short sem_flg;/* operation flags */ sem_flg&IPC_RND 0
};
其中,如果sem_op大于0,那么操作值加入到信号量的值中,并唤醒等待信号增加的进程,如果sem_op为0,当信号量的值是0的时候,函数返回,否则阻塞直到信号量的值为0,如果sem_op小于0,函数判断信号量的值加上这个负值,如果结果为0唤醒等待信号量为0的进程,如果小于0函数阻塞,如果大于0,那么从信号量里面减去这个值并返回。
int semctl (int semid, int semnum, int cmd, union semun arg);
该函数得作用是对信号量进行一系列得控制,semid是要操作得信号量标志,semnum是信号量的下标,cmd是操作的命令,经常用的两个命令是:SETVAL、IPC_RMID,arg用于设置或返回信号量信息。
Union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
void *__pad;
}
- Posix信号灯和SystemV信号灯解析
- Posix信号灯
- Posix有名信号灯
- Posix多线程-信号灯
- IPC通信:Posix信号灯
- IPC通信:Posix信号灯
- 【IPC】Posix信号灯
- 信号灯
- 信号灯
- 信号灯
- 信号灯
- 信号灯
- 信号灯
- Linux编程练习 --SystemV信号灯(信号量)
- UNPv2第十章:Posix信号灯
- 互斥量和信号灯
- Linux semaphore POSIX信号灯的Hello World
- Linux 多线程编程( POSIX )( 三 )------->信号灯
- qemu-kvm虚拟机live迁移源代码解读
- Apache顶级项目8-Geode源码深度分析
- postman
- MySQL事务
- Python学习笔记(2)
- Posix信号灯和SystemV信号灯解析
- C语言:枚举类型的使用详解
- 计算语言学的五个任务中哪个最重要?
- Node.js缓冲器Buffer
- 不会面试的“白帽子”不是好程序员
- 面试题积累篇-简单算法(三)
- jsp页面获取当前的年、月、日
- NCTF 南京邮电大学网络攻防训练平台 WriteUp
- php学习历程