int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set , int signum);
int sigdelset(sigset_t *set , int signum);
int sigismember(const sigset_t *set , int signum);
#include
#include
int main(){
//创建一个信号集
sigset_t set;
//清空信号集的内容
sigemptyset(&set);
//判断SIGINT是否在信号集set里
int ret = sigismember(&set,SIGINT);
if(ret == 0){
printf("SIGINT 不阻塞\n");
}else if(ret == 1){
printf("SIGINT 阻塞\n");
}
//添加几个信号到信号集中
sigaddset(&set,SIGINT);
sigaddset(&set,SIGQUIT);
//判断SIGINT是否在信号集set里
ret = sigismember(&set,SIGINT);
if(ret == 0){
printf("SIGINT 不阻塞\n");
}else if(ret == 1){
printf("SIGINT 阻塞\n");
}
//判断SIGQUIT是否在信号集set里
ret = sigismember(&set,SIGQUIT);
if(ret == 0){
printf("SIGQUIT 不阻塞\n");
}else if(ret == 1){
printf("SIGQUIT 阻塞\n");
}
//从信号集中删除一个信号
sigdelset(&set , SIGQUIT);
//判断SIGQUIT是否在信号集set里
ret = sigismember(&set,SIGQUIT);
if(ret == 0){
printf("SIGQUIT 不阻塞\n");
}else if(ret == 1){
printf("SIGQUIT 阻塞\n");
}
return 0;
}
#include
int sigpromask(int how,const sigset_t *set,sigset_t *oldset);
how:如何对内核阻塞信号集进行处理
SIG_BLOCK:将用户设置的阻塞信号集添加到内核中,内核中原来的数据不变
假设内核中默认的阻塞信号集是mask, mask | set
SIG_UNBLOCK:根据用户设置的数据,对内核中的数据进行解除阻塞
mask &= ~set
SIG_SETMASK:覆盖内核中原来的值
set:已经初始化好的用户自定义的信号集
oldset:保存设置之前的内核中的阻塞信号集的状态,可以是NULL
int sigpending(sigset_t *set);
//编写一个程序,把所有的常规信号(1-31)的未决状态打印到屏幕
//设置某些信号是阻塞的,通过键盘产生这些信号
#include
#include
#include
#include
int main(){
//设置2、3号信号阻塞
sigset_t set;
sigemptyset(&set);
//将2号和3号信号添加到信号集中
sigaddset(&set,SIGINT);
sigaddset(&set,SIGQUIT);
//修改内核中的阻塞信号集
sigprocmask(SIG_BLOCK,&set,NULL);
int num =0;
while(1){
num++;
//获取当前的未决信号集的数据
sigset_t pendingset;
sigemptyset(&pendingset);
sigpending(&pendingset);
//遍历前32位
for(int i = 1;i <= 32 ;i++){
if(sigismember (&pendingset,i) == 1){
printf("1");
}else if(sigismember (&pendingset,i) == 0){
printf("0");
}else{
perror("sigismember");
exit(0);
}
}
printf("\n");
sleep(1);
if(num == 10){
//解除阻塞
sigprocmask(SIG_UNBLOCK,&set,NULL);
}
}
return 0;
}
#include
int sigaction(int signum, const struct siaction *act,struct sigaction *oldact);
struct sigaction {
//函数指针,指向的函数就是信号捕捉到之后的处理函数
void (*sa_handler)(int);
//函数指针,不常用
void (*sa_sigaction)(int, siginfo_t *, void *);
//临时阻塞信号集,在信号捕捉函数执行过程中,临时阻塞某些信号
sigset_t sa_mask;
//使用哪一个信号处理对捕捉到的信号进行处理
//这个值可以是0,表示使用sa_handler,也可以是SA_SIGINFO表示使用sa_sigaction
int sa_flags;
//被废弃掉了
void (*sa_restorer)(void);
};
#include
#include
#include
#include
void myalarm(int num){
printf("捕捉到了信号的编号是:%d\n",num);
printf("XXXXXXXXXX\n");
}
//过3秒以后,每隔2秒定时一次
int main(){
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = myalarm;
sigemptyset(&act.sa_mask); //清空临时阻塞信号集
//注册信号捕捉
sigaction(SIGALRM,&act,NULL);
struct itimerval new_value;
//设置间隔的时间
new_value.it_interval.tv_sec = 2;
new_value.it_interval.tv_usec = 0;
//设置延迟的时间,3秒之后开始第一次定时
new_value.it_value.tv_sec = 3;
new_value.it_value.tv_usec = 0;
int retur = setitimer(ITIMER_REAL ,&new_value,NULL);//非阻塞
printf("定时器开始了...\n");
if(retur == -1){
perror ("setitimer");
exit(0);
}
while(1);
return 0;
}
SIGCHLD信号产生的条件:
以上三种条件都会给父进程发送SIGCHLD信号,父进程默认会忽略该信号
可以用这个信号来解决僵尸进程
#include
#include
#include
#include
#include
#include
void myFun(int num ){
printf("捕捉到的信号:%d\n",num);
//能捕捉到17号信号,可以通过kill -l来查看
//回收子进程PCB的资源
// while(1){
// wait(NULL);
// }
while (1)
{
int ret = waitpid(-1,NULL,WNOHANG);
if(ret > 0){
printf("child die,pid = %d\n",ret);
}else if (ret == 0)
{
//说明还有子进程
break;
}else if (ret == -1)
{
/*没有子进程*/
break;
}
}
}
int main(){
//提前设置好阻塞信号集,阻塞SIGCHLD,因为有可能子进程很快结束,父进程还没有注册完信号捕捉
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGCHLD);
sigprocmask(SIG_BLOCK,&set,NULL);
//创建一些子进程
pid_t pid;
for(int i = 0;i < 20;i++){
pid = fork();
if(pid == 0){
break;
}
}
if(pid > 0){
//父进程
//捕捉子进程死亡时发送的SIGCHLD信号
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = myFun;
sigemptyset(&act.sa_mask);
sigaction(SIGCHLD,&act,NULL);
//注册完信号捕捉后,解除阻塞
sigprocmask(SIG_UNBLOCK,&set,NULL);
while (1)
{
printf("parent process pid :%d\n",getpid());
sleep(2);
}
}else if(pid == 0){
//子进程
printf("child process pid :%d\n",getpid());
}
return 0;
}
共享内存允许两个或者多个进程共享物理内存的同一块区域(通常被称为段)。由于一个共享内存段会称为一个进程用户空间的一部分,因此这种IPC无需内核介入。所有需要做的就是让一个进程将数据复制进共享内存中,并且这部分数据会对其他所有共享同一个段的进程可用
与管道等要求发送进程将数据从用户控件的缓冲区复制进内核内存和接收进程将数据从内核内存复制进用户空间的缓冲区的做法相比,这种IPC技术的速度更快
int shmget(key_t key,size_t size,int shmflg);
void *shmat(int shmid,const void *shmaddr ,int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
key_t ftok(const char *pathname,int proj_id);
int shmget(key_t key,size_t size,int shmflg);
void *shmat(int shmid,const void *shmaddr ,int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
key_t ftok(const char *pathname,int proj_id);
写
#include
#include
#include
#include
int main(){
//1.创建一个共享内存
int shmid = shmget(100,4096,IPC_CREAT|0664);
printf("shmid = %d\n",shmid);
//2.和当前进程进行关联
void * ptr = shmat(shmid, NULL,0);
char* str = "hello world";
//3.写数据
memcpy(ptr,str ,strlen(str)+1);
printf("按任意键继续\n");
getchar();
//4.解除关联
shmdt(ptr);
//5.删除共享内存
shmctl(shmid ,IPC_RMID,NULL);
return 0;
}
读
#include
#include
#include
#include
int main(){
//1.创建一个共享内存
int shmid = shmget(100,0,IPC_CREAT);
printf("shmid = %d\n",shmid);
//2.和当前进程进行关联
void * ptr = shmat(shmid, NULL,0);
//3.读数据
printf("%s\n",(char*)ptr);
printf("按任意键继续\n");
getchar();
//4.解除关联
shmdt(ptr);
//5.删除共享内存
shmctl(shmid ,IPC_RMID,NULL);
return 0;
}
问题1:操作系统如何知道一块共享内存被多少个进程关联
问题2:可不可以对共享内存进行多次删除 shmctl
共享内存和内存映射的区别