嵌入式培训经验分享——进程之间的通讯(常用)

学习进程的创建和释放之后,我们将关心的是进程之间应该如何通讯,下面介绍一下进程之间通讯的三种常用的方法:

1、管道通讯(FIFO)

        FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存储文件系统中。命名管道是一个设备文件,因此即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。

(1)、创建FIFO

#define	MKFIFO_FILE  "/tmp/sharefile"
	
int ret = mkfifo(MKFIFO_FILE,0666|O_CREAT);
	if(ret<0){
		if(errno == EEXIST){
			printf("writer find file exist,do nothing\n");
		}else {
			perror("writer find err");
			exit(-3);
		}
	}

	int fd = open("/tmp/sharefile",O_RDWR);
	if(fd<0){
		perror("reader open err");
		exit(0);
	}


       int mkfifo(路径名字char *path, 文件权限flags )
       #include <sys/types.h>
       #include <sys/stat.h>

       int mkfifo(const char *pathname, mode_t mode);
            pathname:你要创建的文件名字,一般放在/tmp/
            mode:
        返回值:
            0-success
            -1: errno
                    EACCES ,没有权限
                    EEXIST, 文件已存在

(2)、创建一个FIFO,可以理解为创建了一个文件,我们可以用两个不同的进程来打开文件,对文件进行操作等等。采取一个进程存储,一个进程进行读取数据就可以达到通讯的效果。

//写数据
#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>

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

#define	MKFIFO_FILE  "/tmp/sharefile"

struct msg_struct{
	char sex;
	char name[32];
	int age;
	long weight;
	//......................
};

int main()
{
	int ret = mkfifo(MKFIFO_FILE,0666|O_CREAT);
	if(ret<0){
		if(errno == EEXIST){
			printf("writer find file exist,do nothing\n");
		}else {
			perror("writer find err");
			exit(-3);
		}
	}
	
	int fd = open("/tmp/sharefile",O_RDWR);
	if(fd<0){
		perror("writer open err");
		exit(0);
	}
	
	struct msg_struct writemsg;
	while(1){
		writemsg.sex='M';
		strcpy(writemsg.name,"xiaowang");
		writemsg.age=12;
		writemsg.weight=102;
		/*
			如果管道fifo fd中,暂时没有数据,read会在函数内部阻塞等待数据
		*/
		ret = write(fd,&writemsg,sizeof(writemsg));
		if(ret<0){
			perror("writer read err");
			return -34;
		}
		
		sleep(1);
	}
	
	close(fd);
	
	/*删除该文件*/
	unlink("/tmp/sharefile");
}
·
//读数据
#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>

#include <fcntl.h>
#include <unistd.h>
#include <string.h>
 
#define	MKFIFO_FILE  "/tmp/sharefile"

struct msg_struct{
	char sex;
	char name[32];
	int age;
	long weight;
	//......................
};
 
int main()
{
	int ret = mkfifo(MKFIFO_FILE,0666|O_CREAT);
	if(ret<0){
		if(errno == EEXIST){
			printf("reader find file exist,do nothing\n");
		}else {
			perror("reader find err");
			exit(-3);
		}
	}
	
	int fd = open("/tmp/sharefile",O_RDWR);
	if(fd<0){
		perror("reader open err");
		exit(0);
	}
	
	struct msg_struct readmsg;
	while(1){
		memset(&readmsg,0,sizeof(readmsg));
		/*
			如果管道fifo fd中,暂时没有数据,read会在函数内部阻塞等待数据
		*/
		ret = read(fd,&readmsg,sizeof(readmsg));
		if(ret<0){
			perror("reader read err");
			return -34;
		}
		printf("reader got:len = %d name %s sex=%c age=%d weight=%ld\n",\
			ret,readmsg.name,readmsg.sex,readmsg.age,readmsg.weight);
	}
	
	close(fd);
	
	/*删除该文件*/
	unlink("/tmp/sharefile");
}

2、共享内存

共享内存就是在内存中申请一片空间,可以让进程之间相互访问。这样就可以实现进程之间的相互通讯。

申请空间共同访问分为一下几步:

(1)、 创建/获取 共享内存,  没有则创建,有则获取

int shmid = shmget(KEYS_SHM, sizeof( *ptshm),   0666|IPC_CREAT);
	if(shmid == -1){
		perror("shmget err");
		return -34;
	}


      int shmget( int keys,int shmsize, int mode )
       #include <sys/ipc.h>
       #include <sys/shm.h>

       int shmget(key_t key, size_t size, int shmflg);
            key:   共享内存 相关的一个keys, 双方可以通过该keys获取同一片空间
                    他是一个正数
            size: 你要创建/获取 空间的大小
            shmflg: 你想这次如何访问,  r w  
                shmflg它是由32bit构成, 每个bit表示一种属性.  
                     0666,  如果shmflg没有IPC_CREAT,则只是获取系统中已存在的(keys)指定的那个间
                        如果shmflg,有IPC_CREAT, 如果空间已存在直接获取, 不存在则创建
            返回值
                一个共享空间的 id,以后通过该id访问这个内存.
                -1:错误的,errno

(2)、地址映射

	ptshm = shmat(shmid,NULL,0);
	if(ptshm == (void*)-1  ){
		perror("shmat err");
		return 0;
	}

 映射共享空间,到本进程的某个地址,以后通过该地址访问该空间
       #include <sys/types.h>
       #include <sys/shm.h>

       void *shmat(int shmid, const void *shmaddr, int shmflg);
            shmaddr: 如果你想把shm映射到你指定的 地址,你传递该地址即可
                    如果NULL,系统会选择一个地址给你
            shmflg:
                SHM_RDONLY 只读访问
                0  读写    
            返回值:
                成功  一个可以访问shm的地址
                失败  (void *) -1     is returned, 

(3)、在申请空间访问结束之后,我们通常都需要释放该空间,释放该空间分为两步

断开连接:

	int ret=shmdt(ptshm);
	if(ret<0){
		perror("shmdt err");
		return 0;
	}

释放空间:

	ret = shmctl(shmid, IPC_RMID, NULL);
	if(ret<0){
		perror("shmctl err:");
		return -3;
	}

3、信号通讯(又称为软件中断)

 
#include<stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
/*
	signo: 当前发生信号的 num
*/
void sig_intr_handle(int signo )
{
	if(signo == SIGINT){
		printf("I recv SIGINT signal\n");
		//sleep(2);
		//exit(0);
	}else if(signo==SIGSEGV){
		printf("I recv SIGSEGV signal\n");
	}else if(signo == SIGUSR1){
		printf("I recv SIGUSR1 signal\n");
	}else if(signo==SIGUSR2){
		printf("I recv SIGUSR2 signal\n");
		exit(2);
	}
	
} 

int main()
{
	
	signal_handle,该信号的处理方法
	*/
	signal(SIGINT, sig_intr_handle);
	signal(SIGSEGV,sig_intr_handle);
	signal(SIGUSR1,sig_intr_handle);
	signal(SIGUSR2,sig_intr_handle);

	
	while(1){
		
		printf("main process\n");
		sleep(3);
	}
	
}

    /*指定 当进程接收到某种信号的时候,的处理方法 
      #include <signal.h>

       sighandler_t signal(int signum,    void (*signal_handle)(int  )      );
            signum,你要处理的信号

 1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
 6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1    64) SIGRTMAX    

通常我们也用不了这么多,就需要记住一些常用的就行了。

设定完成之后可以使用另一个进程发送信号:

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
int main(int argc,char **argv)
{
	
	int pid = atoi(argv[1]);
	
	while(1){
		
		int ret = kill(pid, 2);
		if(ret<0){
			perror("kill int err");
			return -3;
		}
		sleep(3);
		
		ret = kill(pid, 10);
		if(ret<0){
			perror("kill int err");
			return -3;
		}
		sleep(3);
	}
	
}


        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值