Linux学习-进程间通信

目录

一、概念

二、常用通信方式

三、无名管道(单向)

无名管道创建-pipe:

​编辑

父子进程创建管道示例:

无名管道注意事项:

无名管道的读写特性:

四、有名管道(命名管道)

创建有名管道mkfifo:

打开管道文件:

 两无关进程通信代码案例:

fifow.c 将内容写入管道文件mkfifo中去(mkfifo 根目录下)

fifor.c 输出管道中信息

有名管道特点:

五、内存映射

概念:

mmap()的优点:

函数定义:

注意事项:

mmap()映射的种类:

文件映射:

案例一:映射文件中的内容

​编辑

案例二:两个进程之间的通信

 mmap_w.c 写入:

 mmap_r.c 读取

memcpy函数语法: ​编辑

匿名映射 MAP_ANONYMOUS

案例三:父子间进程通讯  

释放内存映射munmap函数

六、System V 共享内存

System-V IPC:进程间通讯

共享内存

system V 共享内存使用步骤:

1 ftok 生成key

2 创建打开共享内存shmget 返回内存id号 

 3 共享内存映射 - shmat

代码汇总:

   共享内存撤销映射 - shmdt

共享内存控制 - shmctl 

​编辑

七、信号机制

概念:

信号的产生:(软中断)

信号处理方式:   

常用信号:

信号命令kill/killal:

信号的函数:

定时器函数alarm/pause

信号的捕捉 

过程:

 signal函数

​编辑 sigaction函数:

定时器的实现

SIGCHLD回收子进程

信号集、信号屏蔽和阻塞

信号集操作函数

八、消息队列

概念:

消息队列的使用:

消息格式:

九、信号灯/信号量(semaphore)

概念:

三种信号灯:

Posix 有名信号灯和无名信号灯使用:



一、概念

进程和进程之间的信息交换

二、常用通信方式

常用

过时

无名管道(pipe)

System V IPC

有名管道 (fifo)

共享内存(share memory)

⭐信号(signal)

消息队列(message queue)

共享内存(mmap)

信号灯集(semaphore set)

套接字(socket)

共享内存(share memory)

三、无名管道(单向)

无名管道创建-pipe:

#include <unistd.h> //头文件
int pipe(int pfd[2]);

创建时会返回两个文件描述符,分别用于读写管道 

父子进程创建管道示例:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(){
	int pfd[2];
	int re;
	char buf[20]={0};
	pid_t pid;

//make pipe 创建管道
	re = pipe(pfd);
	if(re<0){    
		perror("pipe");//返回创建管道错误信息
		return 0;
	}
//make process 创建进程
	pid = fork();
	if(pid<0){
		perror("fork"); //返回创建进程错误信息
		return 0;
	}else if(pid==0){   //child 子进程
		while(1){
		strcpy(buf,"hahahahahahaa");
     //写入 pfd【1】为写描述符 
		write(pfd[1],buf,strlen(buf));
		sleep(1); //休眠1秒钟
		}
	}else{
//father 父进程
		while(1){
     //读取 pfd【0】为读描述符
			re = read(pfd[0],buf,20);
			if(re>0){
				printf("read pipe=%s\n",buf);
			}
		}		
	}
}

无名管道注意事项:

1.只能用于亲缘关系的进程间通信(父子进程,兄弟进程)

2.管道通信是单向的,一端读,一端写(程序实现设计好)

3.数据不能自己读自己写

4.管道可以用于大于2个进程共享

#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(){
    int pfd[2];
    int i;
    int re;
    char buf[40]={0};
    pid_t pid;
    //make pipe 创建管道
    re = pipe(pfd);
    if(re<0){
        perror("pipe");
        return 0;
    }
    //输出 读输出符 写输出符
    printf("%d,%d\n",pfd[0],pfd[1]);
//循环 创建两个子进程
    for(i=0;i<2;i++){
        pid = fork();
        if(pid<0){ 
            perror("fork");  //打印进程创建错误信息
            return 0;
        }else if(pid>0){  //父进程
        }else{ 
            break;  //不创建子进程    
        }
    }
    if(i==2){  //主进程
        close(pfd[1]);  //关闭写端
        while(1){
            memset(buf,0,40); //清除 buf中的数据
            re=read(pfd[0],buf,40) ;//打开读端
            if(re>0){
                printf("%s\n",buf);
            }    
        }
        return 0;
    }
    if(i==1){  //子进程1
        close(pfd[0]);  //关闭读端
        while(1){
            strcpy(buf,"this is 2 process"); 
            write(pfd[1],buf,strlen(buf)); //打开写端
            usleep(930000);
        }
        return 0;
    }
    if(i==0){  //子进程2
        close(pfd[0]); //关闭读端
        while(1){
            strcpy(buf,"this is 1 process");
            write(pfd[1],buf,strlen(buf)); //打开写端
            sleep(1);
        }
        return 0;
    }


}

 

无名管道的读写特性:

1.读管道:pfd[0]

· 管道中有数据,read返回实际读到的字节数

· 管道写端被全部关闭,read返回0

写端没有全部被关闭,但也不写,read阻塞等待

2.写管道:pfd[1]

· 管道读端全部被关闭,进程异常终止 close(pfd[1]) close(pfd[0])

· 管道读端没有全部关闭:

管道已满,write阻塞

管道未满, write将数据写入 并返回实际写入的字节数

四、有名管道(命名管道)

创建有名管道mkfifo:

       #include <sys/types.h>
       #include <sys/stat.h>
        
       int mkfifo(const char *filename, mode_t mode);

打开管道文件:

文件IO方式打开

open(const char *path, O_RDONLY);//1

open(const char *path, O_RDONLY | O_NONBLOCK);//2 非阻塞

open(const char *path, O_WRONLY);//3

open(const char *path, O_WRONLY | O_NONBLOCK);//4 非阻塞

 两无关进程通信代码案例:

fifow.c 将内容写入管道文件mkfifo中去(mkfifo 根目录下)

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

int main(){
//创建有名管道
        int re;
        int fd;
        re = mkfifo("/myfifo",0666);
        if(re<0){
                perror("mkfifo");
           //     return 0;
        }
//打开管道文件 
    fd = open("/myfifo",O_WRONLY); // 只写方式打开
    if(fd<0){
        perror("open");
        return 0;
    }
//将信息写道管道里面去
    while(1){
        fgets(buf,32,stdin);//从键盘输入读取
        write(fd,buf,strlen(buf));
    }   
}

fifor.c 输出管道中信息

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

int main(){
        int fd;
        int re;
//打开管道文件
    fd = open("/myfifo",O_RDONLY); // 只读方式打开
    if(fd<0){
        perror("open");
        return 0;
    }
//将管道信息读出
    while(1){
        read(fd,buf,32);
        if(re>0){
            printf("read fifo=%s\n",buf);
        }else if(re==0){
            exit(0);
        }
    }   
}

有名管道特点:

1有名管道可以使非亲缘的两个进程互相通信

2通过路径名来操作,在文件系统中可见,但内容存放在内存中

3 文件IO来操作有名管道

4 遵循先进先出规则

5 不支持leek操作

6 单工读写

五、内存映射

概念:

  • 共享内存可以通过mmap()映射普通文件
  • 使一个磁盘文件与内存中的一个缓冲区相映射,进程可以像访问普通内存一样对文件进行访问,不必再调用read,write。

mmap()的优点:

用户空间和内核空间的高效交互方式

函数定义:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 
  • 功能:创建共享内存映射
  • 函数返回值:成功返回创建的映射区首地址,失败返回MAP_FAILED (((void *) -1) ),设置errno值
  • 参数说明:
  1. addr:指定要映射的内存地址,一般设置为 NULL 让操作系统自动选择合适的内存地址。
  2. length:必须>0。映射地址空间的字节数,它从被映射文件开头 offset 个字节开始算起。
  3. prot:指定共享内存的访问权限。可取如下几个值的可选:PROT_READ(可读), PROT_WRITE(可写), PROT_EXEC(可执行), PROT_NONE(不可访问)。
  4. flags:由以下几个常值指定: 映射区权限MAP_SHARED(共享的) MAP_PRIVATE(私有的), MAP_FIXED(表示必须使用 start 参数作为开始地 址,如果失败不进行修正),其中,MAP_SHARED , MAP_PRIVATE必选其一,而 MAP_FIXED 则不推荐使 用。MAP_ANONYMOUS(匿名映射,用于血缘关系进程间通信)
  5. fd:表示要映射的文件句柄。如果匿名映射写-1
  6. offset:表示映射文件的偏移量,一般设置为 0 表示从文件头部开始映射。

注意事项:

(1)创建映射区的过程中,隐含着一次对映射文件的读操作,将文件内容读取到映射区。

(2)当MAP_SHARED时,要求:映射区的权限应 <=文件打开的权限(出于对映射区的保护),如果不满足报非法参数(Invalid argument)错误。

当MAP_PRIVATE时候,mmap中的权限是对内存的限制,只需要文件有读权限即可,操作只在内存有效,不会写到物理磁盘,且不能在进程间共享。

(3)映射区的释放与文件关闭无关,只要映射建立成功,文件可以立即关闭。任然可以读 写

(4)用于映射的文件大小必须>0,当映射文件大小为0时,指定非0大小创建映射区,访问映射地址会报总线错误,指定0大小创建映射区,报非法参数错误(Invalid argument)

(5)文件偏移量必须为0或者4K的整数倍(不是会报非法参数Invalid argument错误).

(6)映射大小可以大于文件大小,但只能访问文件page的内存地址,否则报总线错误,超出映射的内存大小报段错误。

mmap()映射的种类:

  1. 文件映射:文件映射将一个文件的一部分直接映射到调用mmap()进程的虚拟内存中去。当一个文件被映射之后,就可以通过对该内存区域中的字节进行操作,从而实现对文件的读写操作。这种映射被称为基于文件的映射或内存映射文件。
  2. 匿名映射:匿名映射没有对应的文件。可以把它看成是一个内容被初始化为0的虚拟文件的映射。

文件映射:

案例一:映射文件中的内容

#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

int main(){

    void* addr;

    int fd;
    fd = open("test",O_RDWR);
    if(fd<0){
        perror("open");
        return 0;
    }

    addr = mmap(NULL, 1000, PROT_READ|PROT_WRITE ,MAP_SHARED, fd, 0);
    if (addr == MAP_FAILED){
           perror("mmap");
           return 0;
       }
    //	memcpy(addr,"abcdef",7);

    printf("read=%s\n",(char*)addr);


}

mmap建立映射空间将test文本中的内容打印出来

案例二:两个进程之间的通信

 mmap_w.c 写入:

#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

int main(){
	void* addr;
	int fd;
	int i =0;
	fd = open("test",O_RDWR);
	if(fd<0){
		perror("open");
		return 0;
	}
//	int len = lseek(fd,0,SEEK_END);
	addr = mmap(NULL, 2048, PROT_READ|PROT_WRITE , MAP_SHARED, fd, 0);
       if (addr == MAP_FAILED){
       	perror("mmap");
	     return 0;
       }
       close(fd);
       while(i<2048){
		memcpy((addr+i),"a",1);
		i++;
		sleep(1);
       }
//	printf("read=%s\n",(char*)addr);

}

 mmap_r.c 读取

#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>


int main(){
	
	void* addr;

	int fd;
	fd = open("test",O_RDWR);
	if(fd<0){
		perror("open");
		return 0;
	}
	
	int len = lseek(fd,0,SEEK_END); //返回文件大小
	
	addr = mmap(NULL, len, PROT_READ|PROT_WRITE , MAP_SHARED, fd, 0);
	
       if (addr == MAP_FAILED){
       	perror("mmap");
	return 0;
       }

       close(fd);

//	memcpy(addr,"abcdef",10);
	while(1){
		printf("read=%s\n",(char*)addr);
		sleep(1);
	}


}

memcpy函数语法: 

 

匿名映射 MAP_ANONYMOUS

案例三:父子间进程通讯  

#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>


int main(){
	
	void* addr;
	
	addr = mmap(NULL,2048, PROT_READ|PROT_WRITE , MAP_SHARED| MAP_ANONYMOUS, -1, 0);
       if (addr == MAP_FAILED){
       	perror("mmap");
		return 0;
       }
  
	//创建进程
    pid_t pid;
    pid = fork();
    if(pid<0){
        perror("fork");
        return 0;
    }
    
    //父进程
    else if(pid>0){
    	memcpy(addr,"1234567890",10);
        wait(NULL);
    }
    //子进程
    else{
    	sleep(1);
        printf("read father val=%s\n",(char*)addr);
    }
    
}

释放内存映射munmap函数

int munmap(void *addr, size_t length);

返回值:成功返回0,失败返回-1,并设置errno值。

函数参数:

addr:调用mmap函数成功返回的映射区首地址

length:映射区大小(即:mmap函数的第二个参数)

六、System V 共享内存

System-V IPC:进程间通讯

 

共享内存

直接访问内核,避免了应用程序从内核空间访问到用户空间 

system V 共享内存使用步骤:

1 ftok 生成key

#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>

int main(){
    key_t key;
    int shmid;
    char *buf;
    key = ftok("keytest",100);
    if(key<0){
        perror("ftok");
        return 0;
    }
    printf("key=%x\n",key);
}

 

2 创建打开共享内存shmget 返回内存id号 

 

#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>

int main(){
    key_t key;
    int shmid;
    char *buf;
    key = ftok("keytest",100);
    if(key<0){
        perror("ftok");
        return 0;
    }
    printf("key=%x\n",key);

    shmid = shmget(key,512,IPC_CREAT|0666);

    if(shmid<0){
        perror("shmget");
        return 0;
    }
    
    printf("shmid=%d\n",shmid);
}

 3 共享内存映射 - shmat

 

#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>

int main(){
    key_t key;
    int shmid;
    char *buf;
    key = ftok("keytest",100);
    if(key<0){
        perror("ftok");
        return 0;
    }
    printf("key=%x\n",key);

    shmid = shmget(key,512,IPC_CREAT|0666);

    if(shmid<0){
        perror("shmget");
        return 0;
    }
    
    printf("shmid=%d\n",shmid);

    //-------------------------------------
    buf = shmat(shmid,NULL,0);
    if(buf<0){
        perror("shmat");
        return 0;
    }    
    strcpy(buf,"hello world");
    
}

代码汇总:

        写入共享内存:     shm_w.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
int main(){
    key_t key;
    int shmid;
    char *buf;
    //生成key
    key = ftok("keytest",100);
    if(key<0){
        perror("ftok");
        return 0;
    }
    printf("key=%x\n",key);
	//创建共享内存 返回 id号
    shmid = shmget(key,512,IPC_CREAT|0666);
    if(shmid<0){
        perror("shmget");
        return 0;
    } 
    printf("shmid=%d\n",shmid);
    //共享内存映射 
    buf = shmat(shmid,NULL,0);
    if(buf<0){
        perror("shmat");
        return 0;
    }    
    //buf 是地址 写入内容
    strcpy(buf,"hello world");
    
}

         读出共享内存: shm_r.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>

int main(){
    key_t key;
    int shmid;
    char *buf;
    key = ftok("keytest",100);
    if(key<0){
        perror("ftok");
        return 0;
    }
    printf("key=%x\n",key);
//不用再创建
    shmid = shmget(key,512,0666);

    if(shmid<0){
        perror("shmget");
        return 0;
    }    
    printf("shmid=%d\n",shmid);
   
    buf = shmat(shmid,NULL,0);
    if(buf<0){
        perror("shmat");
        return 0;
    }    
//读取
    printf("share mem=%s\n",buf);
    while(1){
        sleep(1);
    }    
//撤销映射
    shmdt(buf);
//删除
    shmctl(shmid, IPC_RMID, NULL);


}

   共享内存撤销映射 - shmdt

共享内存控制 - shmctl 

 

七、信号机制

概念:

信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式;

linux内核通过信号通知用户进程,所有信号的产生及处理全部都是由内核完成的,不同的信号类型代表不同的事件;

linux对早期的unix信号机制进行了扩展

信号的产生:(软中断)

信号处理方式:   

  1. 缺省方式
  2. 忽略信号
  3. 捕捉信号

常用信号:

信号名

含义

默认操作

SIGHUP

该信号在用户终端关闭时产生,通常是发给和该

终端关联的会话内的所有进程

终止

SIGINT

该信号在用户键入INTR字符(Ctrl-C)时产生,内

核发送此信号送到当前终端的所有前台进程

终止

SIGQUIT

该信号和SIGINT类似,但由QUIT字符(通常是

Ctrl-\)来产生

终止

SIGILL

该信号在一个进程企图执行一条非法指令时产生

终止

SIGSEV

该信号在非法访问内存时产生,如野指针、缓

冲区溢出

终止

SIGPIPE

当进程往一个没有读端的管道中写入时产生,代

表“管道断裂”

终止

信号名

含义

默认操作

SIGKILL

该信号用来结束进程,并且不能被捕捉和忽略

终止

SIGSTOP

该信号用于暂停进程,并且不能被捕捉和忽略

暂停进程

SIGTSTP

该信号用于暂停进程,用户可键入SUSP字符(

通常是Ctrl-Z)发出这个信号

暂停进程

SIGCONT

该信号让进程进入运行态

继续运行

SIGALRM

该信号用于通知进程定时器时间已到

终止

SIGUSR1/2

该信号保留给用户程序使用

终止

SIGCHLD

是子进程状态改变发给父进程的。

信号命令kill/killal:

信号的函数:

定时器函数alarm/pause

 int alarm (unsigned int seconds);
●  成功时返回上个定时器的剩余时间,失败时返回EOF
● seconds定时器的时间
● 一个进程中只能设定一个定时器,时间到产生SIGALRM
int pause(void);
暂停
● 进程一直阻塞,直到被信号中断
● 被信号终端后返回-1,errno为EINTR

信号的捕捉 

过程:

  1. 定义新的信号的执行函数handle。
  2. 使用signal/sigaction函数,把自定义的handle和指定的信号相关联。

 signal函数

 头文件: typedef void (*sighandler_t)(int); 
sighandler_t  signal(int signum, sighandler_t handler); 

功能:捕捉信号执行自定义函数
返回值:成功时返回原先的信号处理函数,失败时返回SIG_ERR(写入新的行为,返回旧的行为)
signum 要设置的信号类型
handler 指定的信号处理函数: SIG_DFL代表缺省方式; SIG_IGN 代表忽略信号;  

 sigaction函数:

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
结构体:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
参数:
signum:处理的信号
act,oldact: 处理信号的新行为和旧的行为,是一个sigaction结构体。

sigaction结构体成员定义如下:
sa_handler:是一个函数指针,其含义与 signal 函数中的信号处理函数类似
sa_sigaction:另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。
sa_flags参考值如下:
SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数
SA_RESTART:使被信号打断的系统调用自动重新发起。
SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。
re_restorer:是一个已经废弃的数据域
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/posix_types.h>

typedef void (*sighandler_t)(int);

sighandler_t oldact;

void handle(int sig){
	printf("i cath the SIGINT \n");
//	signal(SIGINT,oldact);
}

int main(){
    //填结构体内容
	struct sigaction act;
	act.sa_handler = handle;
	act.sa_flags = 0;
    //清空内容
    sigemptyset(&act.sa_mask);
    
	sigaction(SIGINT,&act,NULL);


	while(1){
		sleep(1);
	}
}

定时器的实现

unsigned int alarm(unsigned int seconds);
功能:定时发送SIGALRM给当前进程
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
功能:定时的发送alarm信号
参数:int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
功能:定时的发送alarm信号
参数:
which:  
· ITIMER_REAL:以逝去时间递减。发送SIGALRM信号
· ITIMER_VIRTUAL: 计算进程(用户模式)执行的时间。发送SIGVTALRM信号
· ITIMER_PROF: 进程在用户模式(即程序执行时)和核心模式(即进程调度用时)均计算时间。发送SIGPROF信号
new_value:  负责设定 timout 时间                
old_value:  存放旧的timeout值,一般指定为NULL
struct itimerval {
struct timeval it_interval;  // 闹钟触发周期
struct timeval it_value;    // 闹钟触发时间
};
struct timeval { 		//结构体里的结构体
time_t      tv_sec;         /* seconds */
suseconds_t tv_usec;        /* microseconds */
};
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/posix_types.h>
#include <sys/time.h>

typedef void (*sighandler_t)(int);

sighandler_t oldact;

void handle(int sig){
	if(sig == SIGINT)
	{
		printf("i cath the SIGINT \n");
	}
	else if (sig==SIGALRM)
	{
		printf("second timer \n");
//		alarm(1);
	}
//	signal(SIGINT,oldact);
}

int main(){
	struct sigaction act;
	act.sa_handler = handle;
	act.sa_flags = 0;

       	sigemptyset(&act.sa_mask);

	sigaction(SIGINT,&act,NULL);
//	alarm(1);
//	
	struct itimerval timevalue;
    //触发周期
	timevalue.it_interval.tv_sec = 1;
	timevalue.it_interval.tv_usec = 0;
    //触发时间
	timevalue.it_value.tv_sec = 5;
    timevalue.it_value.tv_usec = 0;


	setitimer(ITIMER_REAL, &timevalue, NULL);

	sigaction(SIGALRM,&act,NULL);

	while(1){
//		sleep(1);
	}
}

SIGCHLD回收子进程

#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>

void handle(int sig){
	wait(NULL);
	printf("Get sig = %d\n",sig);
}

int main(){
	pid_t pid;
	struct sigaction act;
	act.sa_handler = handle;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);

	pid = fork();

	if(pid>0){
		//wait(NULL); 父进程
		sigaction(SIGCHLD,&act,NULL);
		while(1){
			printf("this is father process\n");
			sleep(1);
		}
	} //子进程
    else if(pid == 0){
		sleep(3);
		exit(0);
	}

}

信号集、信号屏蔽和阻塞

有时候不希望在接到信号时就立即停止当前执行,去处理信号,同时也不希望忽略该信号,而是延时一段时间去调用信号处理函数。这种情况可以通过阻塞信号实现。

信号的阻塞概念:信号的”阻塞“是一个开关动作,指的是阻止信号被处理,但不是阻止信号产生。

信号的状态:

  1.     信号递达(Delivery ):实际信号执行的处理过程(3种状态:忽略,执行默认动作,捕获)
  2.     信号未决(Pending):从产生到递达之间的状态

信号集操作函数

sigset_t set; 自定义信号集。 是一个32bit 64bit 128bit的数组。

sigemptyset(sigset_t *set); 清空信号集

sigfillset(sigset_t *set); 全部置1

sigaddset(sigset_t *set, int signum); 将一个信号添加到集合中

sigdelset(sigset_t *set, int signum); 将一个信号从集合中移除

sigismember(const sigset_t *set,int signum); 判断一个信号是否在集合中。

设定对信号集内的信号的处理方式(阻塞或不阻塞)

八、消息队列

概念:

进程通讯的一种手段。

  • 消息队列是System V IPC对象的一种
  • 消息队列由消息队列ID来唯一标识
  • 消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息
  • 消息队列可以按照类型来发送、接受消息

消息队列的使用:

  • 打开/创建消息队列 msgget
  • 向消息队列发送消息 msgsnd
  • 从消息队列接收消息 msgrcv
  • 控制消息队列 msgctl

消息格式:

发送端:

  1. 申请Key
  2. 打开/创建消息队列 msgget
  3. 向消息队列发送消息 msgsnd

接收端:

  1. 打开/创建消息队列 msgget
  2. 从消息队列接受消息 msgrcv
  3. 控制(删除)消息队列 msgctl

九、信号灯/信号量(semaphore)

概念:

  1. 信号量代表一类资源,其值表示系统中该资源的数量
  2. 信号量是一个受保护的变量,只能通过三种操作来访问
    1. 初始化
    2. P操作(申请资源)- 消费者 -1
    3. V操作(释放资源)- 生产者 +1

三种信号灯:

  • Posix 有名信号灯
  • Posix 无名信号灯 (linux只支持线程同步)
  • System V 信号灯

Posix 有名信号灯和无名信号灯使用:

未完待续

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值