不只是sem.h,很多头文件都有/usr/include/linux和/usr/include/sys两个版本。
我的印象是:linux目录里面的头文件用于内核,
sys目录里面的头文件用于应用程序或者glibc标准库
如果我的回答没能帮助您,请继续追问。
信号量:一个整数;大于或等于0时代表可供并发进程使用的资源实体数;
小于0时代表正在等待使用临界区的进程数;
用于互斥的信号量初始值应大于0;
只能通过P、V原语操作而改变;
信号量元素组成:
1、表示信号量元素的值;
2、最后操作信号量元素的进程ID
3、等待信号量元素值+1的进程数;
4、等待信号量元素值为0的进程数;
二、主要函数
1.1 创建信号量
int semget(
key_t key, //标识信号量的关键字,有三种方法:1、使用IPC——PRIVATE让系统产生,
// 2、挑选一个随机数,3、使用ftok从文件路径名中产生
int nSemes, //信号量集中元素个数
int flag //IPC_CREAT;IPC_EXCL 只有在信号量集不存在时创建
)
成功:返回信号量句柄
失败:返回-1
1.2 使用ftok函数根据文件路径名产生一个关键字
key_t ftok(const char *pathname,int proj_id)
路径名称必须有相应权限
1.3 控制信号量
int semctl(
int semid, //信号量集的句柄
int semnum, //信号量集的元素数
int cmd, //命令
/*union senum arg */... //
)
成功:返回相应的值
失败:返回-1
命令详细说明:
cmd: IPC_RMID 删除一个信号量
IPC_EXCL 只有在信号量集不存在时创建
IPC_SET 设置信号量的许可权
SETVAL 设置指定信号量的元素的值为 agc.val
GETVAL 获得一个指定信号量的值
GETPID 获得最后操纵此元素的最后进程ID
GETNCNT 获得等待元素变为1的进程数
GETZCNT 获得等待元素变为0的进程数
union senum 定义如下:
union senum{
int val
struct semid_ds *buf
unsigned short * array
}agc
其中 semid_ds 定义如下:
struct semid_ds{
struct ipc_pem sem_pem //operation pemission struct
time_t sem_otime //last semop()time
time_t sem_ctime //last time changed by semctl()
struct sem *sembase //ptr to first semaphore in array
struct sem_queue *sem_pending//pending operations
struct sem_queue *sem_pending_last//last pending operations
struct sem_undo *undo //undo requests on this arrary
unsigned short int sem_nsems//number of semaphores in set
}
1.4 对信号量 +1 或 -1 或测试是否为0
int semop(
int semid,
struct sembuf *sops, //指向元素操作数组
unsigned short nsops //数组中元素操作的个数
)
结构 sembuf 定义
sembuf{
short int sem_num//semaphore number
short int sem_op//semaphore operaion
short int sem_flg //operation flag
}
三、例子:
2.1 服务器
#include <sys/sem.h>
#include <sys/ipc.h>
#define SEGSIZE 1024
#define READTIME 1
union semun {
int val
struct semid_ds *buf
unsigned short *array
} arg
//生成信号量
int sem_creat(key_t key)
{
union semun sem
int semid
sem.val = 0
semid = semget(key,1,IPC_CREAT|0666)
if (-1 == semid){
printf("create semaphore error\n")
exit(-1)
}
semctl(semid,0,SETVAL,sem)
return semid
}
//删除信号量
void del_sem(int semid)
{
union semun sem
sem.val = 0
semctl(semid,0,IPC_RMID,sem)
}
//p
int p(int semid)
{
struct sembuf sops={0,+1,IPC_NOWAIT}
return (semop(semid,&sops,1))
}
//v
int v(int semid)
{
struct sembuf sops={0,-1,IPC_NOWAIT}
return (semop(semid,&sops,1))
}
int main()
{
key_t key
int shmid,semid
char *shm
char msg[7] = "-data-"
char i
struct semid_ds buf
key = ftok("/",0)
shmid = shmget(key,SEGSIZE,IPC_CREAT|0604)
if (-1 == shmid){
printf(" create shared memory error\n")
return -1
}
shm = (char *)shmat(shmid,0,0)
if (-1 == (int)shm){
printf(" attach shared memory error\n")
return -1
}
semid = sem_creat(key)
for (i = 0i <= 3i++){
sleep(1)
p(semid)
sleep(READTIME)
msg[5] = '0' + i
memcpy(shm,msg,sizeof(msg))
sleep(58)
v(semid)
}
shmdt(shm)
shmctl(shmid,IPC_RMID,&buf)
del_sem(semid)
return 0
//gcc -o shm shm.c -g
}
2.2 客户端
#include <sys/sem.h>
#include <time.h>
#include <sys/ipc.h>
#define SEGSIZE 1024
#define READTIME 1
union semun {
int val
struct semid_ds *buf
unsigned short *array
} arg
// 打印程序执行时间
void out_time(void)
{
static long start = 0
time_t tm
if (0 == start){
tm = time(NULL)
start = (long)tm
printf(" now start ...\n")
}
printf(" second: %ld \n",(long)(time(NULL)) - start)
}
//创建信号量
int new_sem(key_t key)
{
union semun sem
int semid
sem.val = 0
semid = semget(key,0,0)
if (-1 == semid){
printf("create semaphore error\n")
exit(-1)
}
return semid
}
//等待信号量变成0
void wait_v(int semid)
{
struct sembuf sops={0,0,0}
semop(semid,&sops,1)
}
int main(void)
{
key_t key
int shmid,semid
char *shm
char msg[100]
char i
key = ftok("/",0)
shmid = shmget(key,SEGSIZE,0)
if(-1 == shmid){
printf(" create shared memory error\n")
return -1
}
shm = (char *)shmat(shmid,0,0)
if (-1 == (int)shm){
printf(" attach shared memory error\n")
return -1
}
semid = new_sem(key)
for (i = 0i <3i ++){
sleep(2)
wait_v(semid)
printf("Message geted is: %s \n",shm + 1)
out_time()
}
shmdt(shm)
return 0
// gcc -o shmc shmC.c -g
}
信号量在进程是以有名信号量进行通信的,在线程是以无名信号进行通信的,因为线程linux还没有实现进程间的通信,所以在sem_init的第二个参数要为0,而且在多线程间的同步是可以通过有名信号量也可通过无名信号,但是一般情况线程的同步是无名信号量,无名信号量使用简单,而且sem_t存储在进程空间中,有名信号量必须LINUX内核管理,由内核结构struct ipc_ids 存储,是随内核持续的,系统关闭,信号量则删除,当然也可以显示删除,通过系统调用删除,消息队列,信号量,内存共享,这几个都是一样的原理。,只不过信号量分为有名与无名
无名使用 <semaphore.h>,
有名信号量<sys/sem.h>
无名信号量不能用进程间通信,
//无名与有名的区别,有名需要KEY值与IPC标识
所以sem_init的第二个参数必须为0,,,,
欢迎分享,转载请注明来源:夏雨云
评论列表(0条)