Linux进程间通信之信号量
一.信号量
定义信号变量; sem_t sem1 sem2
初始化信号量
P操作
V操作
功能 信号量(POSOX) 信号量灯(IPC)
定义信号变量 sem_t sem1 semget
初始化信号量 sem_init semctl
P操作 sem_wait semop
V操作 sem_post semop
前面学的信号量时针对的是单个的信号。而信号灯集是一个整体的概念是针对的多个信号量来操作的。
信号灯:
信号灯集合(可以包含多个信号灯) IPC对象是一个信号灯集(多个信号量)
1.semget
int semget(key_t key, int nsems, int semflg);
所需头文件 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数原型 int semget(key_t key, int nsems, int semflg);
函数参数 key:和信号灯集关联的key值
nsems: 信号灯集中包含的信号灯数目
semflg:信号灯集的访问权限
函数返回值
成功:信号灯集ID
出错:-1
2.semop
所需头文件 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数原型 int semop ( int semid, struct sembuf *opsptr, size_t nops);
函数参数 semid:信号灯集ID
struct sembuf {
short sem_num; // 要操作的信号灯的编号
short sem_op; // 0 : 等待,直到信号灯的值变成0
// 1 : 释放资源,V操作
// -1 : 分配资源,P操作
short sem_flg; // 0(阻塞), IPC_NOWAIT, SEM_UNDO
};
nops: 要操作的信号灯的个数
函数返回值
成功:0
出错:-1
3.semctl
所需头文件 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数原型 int semctl ( int semid, int semnum, int cmd,…union semun arg(不是地址));
函数参数 semid:信号灯集ID
semnum: 要修改的信号灯编号
cmd: GETVAL:获取信号灯的值
SETVAL:设置信号灯的值
IPC_RMID:从系统中删除信号灯集合
函数返回值
成功:0
出错:-1
semctl:cmd:
GETVAL:获取信号灯的值
SETVAL:设置信号灯的值
IPC_RMID:从系统中删除信号灯集合
msgctl:cmd IPC_STAT (获取对象属性)
shmctl:cmd IPC_SET (设置对象属性)
#include "sys/types.h"
#include "sys/sem.h"
#include "signal.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
int semid;
semid=semget(IPC_PRIVATE,3,0777);
if(semid <0)
{
printf("creat semaphore failure\n");
return -1;
}
printf("creat semaphore sucess semid=%d\n",semid);
system("ipcs -s");
//while(1);
// delete semaphore
semctl(semid,0,IPC_RMID,NULL);
system("ipcs -s");
return 0;
}
SETVAL:设置信号灯的值 信号灯的初始化,类似sem_init;
union semun
{
int val;
//SETVAL:设置信号灯的值
struct semid_ds *buf;
// IPC_STAT (获取对象属性)
//IPC_SET (设置对象属性)
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
};
通过POSOX实现同步信号:
PV操作
#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
#include "semaphore.h"
#include <unistd.h>
sem_t sem;
void *fun(void *var)//child thread code
{
int j;
//p wait
sem_wait(&sem); //sleep
for(j=0;j<10;j++)//second
{
usleep(100);
printf("this is fun j=%d\n",j);
}
}
int main()//main thread code
{
int i;
char str[]="hello linux\n";
pthread_t tid;
int ret;
sem_init(&sem,0,0);//sem=0
ret=pthread_create(&tid,NULL,fun,(void *)str);
if(ret<0)
{
printf("creat thread failure\n");
return -1;
}
for(i=0;i<10;i++)//first
{
usleep(100);
printf("this is main fun i=%d\n",i);
}
//v
sem_post(&sem);
while(1);
return 0;
}
利用信号灯集实现同步通信
#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
//#include "semaphore.h"
#include "sys/ipc.h"
#include "sys/sem.h"
#include <unistd.h>
//sem_t sem;
union semun
{
int val; /* Value for SETVAL*/
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
int semid;
union semun mysemun;
struct sembuf mysembuf;
void *fun(void *var)//child thread code
{
int j;
//p wait
// sem_wait(&sem); //sleep
mysembuf.sem_op=-1;
semop(semid,&mysembuf,1);
for(j=0;j<10;j++)//second
{
usleep(100);
printf("this is fun j=%d\n",j);
}
}
int main()//main thread code
{
int i;
char str[]="hello linux\n";
pthread_t tid;
int ret;
semid=semget(IPC_PRIVATE,3,0777);
if(semid < 0)
{
printf("creat semaphore failure\n");
return -1;
}
printf("creat semaphore sucess,semid=%d\n",semid);
system("ipcs -s");
mysemun.val=0;
semctl(semid,0,SETVAL,mysemun);
//sem_init(&sem,0,0);//sem=0
mysembuf.sem_num=0;
mysembuf.sem_flg=0;
ret=pthread_create(&tid,NULL,fun,(void *)str);
if(ret<0)
{
printf("creat thread failure\n");
return -1;
}
for(i=0;i<10;i++)//first
{
usleep(100);
printf("this is main fun i=%d\n",i);
}
//v
// sem_post(&sem);
mysembuf.sem_op=1;
semop(semid,&mysembuf,1);
while(1);
return 0;
}
之前我们是通过posix中的信号量在操作,后来我们是通过IPC机制的sem灯在操作。
接下来我们通过ftok函数用信号灯集实现无亲缘关系的通信。
clinet.c
#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
//#include "semaphore.h"
#include "sys/ipc.h"
#include "sys/sem.h"
#include <unistd.h>
//sem_t sem;
union semun
{
int val; /* Value for SETVAL*/
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
int semid;
union semun mysemun;
struct sembuf mysembuf;
int main()//main thread code
{
int i;
int key;
key=ftok("./a.c",'a');
if(key < 0)
{
printf("creat key failure\n");
return -1;
}
printf("creat key sucess \n");
semid=semget(key,3,IPC_CREAT | 0777);//IPC_EXCL
if(semid < 0)
{
printf("creat semaphore failure\n");
return -2;
}
printf("creat semaphore sucess,semid=%d\n",semid);
system("ipcs -s");
//init sem
mysemun.val=0;
semctl(semid,0,SETVAL,mysemun);
mysembuf.sem_num=0;
mysembuf.sem_flg=0;
//P wait
mysembuf.sem_op=-1;
semop(semid,&mysembuf,1);
for(i=0;i<10;i++)//second
{
usleep(100);
printf("this is main fun i=%d\n",i);
}
//V
//mysembuf.sem_op=1;
//semop(semid,&mysembuf,1);
while(1);
return 0;
}
server.c
#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"
//#include "semaphore.h"
#include "sys/ipc.h"
#include "sys/sem.h"
#include <unistd.h>
//sem_t sem;
union semun
{
int val; /* Value for SETVAL*/
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
int semid;
union semun mysemun;
struct sembuf mysembuf;
int main()//main thread code
{
int i;
int key;
key=ftok("./a.c",'a');
if(key < 0)
{
printf("creat key failure\n");
return -1;
}
printf("creat key sucess \n");
semid=semget(key,3,IPC_CREAT | 0777);//IPC_EXCL
if(semid < 0)
{
printf("creat semaphore failure\n");
return -2;
}
printf("creat semaphore sucess,semid=%d\n",semid);
system("ipcs -s");
//init sem
//mysemun.val=0;
//semctl(semid,0,SETVAL,mysemun);
mysembuf.sem_num=0;
mysembuf.sem_flg=0;
for(i=0;i<10;i++)//first
{
usleep(100);
printf("this is main fun i=%d\n",i);
}
//V
mysembuf.sem_op=1;
semop(semid,&mysembuf,1);
while(1);
return 0;
}
这个时候是我么的客户端先运行,客户端处于一种阻塞的状态,接着运行服务器端时,服务器先打印10条语句,再是客户端打印10条语句。