linux系统编程之进程间通信

一、管道

无名管道

pipe.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
//int pipe(int fd[2]);    // 返回值:若成功返回0,失败返回-1

int main()
{

	int fd[2];
	int ret;
	pid_t PID;
	int n_read;
	int n_write;
	char *buf= (char*)malloc(128);
	//创建无名管道
	if ( (ret = pipe(fd)) == -1 )
	{
		printf("create pipe failed\n");
		return -1;
	}

	//创建子进程
	PID = fork();

	//father process write string
	
	if( PID > 0)//父进程
	{
       
		close(fd[0]);// 关闭读端
        
		n_write = write(fd[1],"hello boy from father",strlen("hello boy from father"));//开启写端,写入管道
		printf("write %d byte success\n",n_write);
		wait(NULL);
	
	}
	else if(PID == 0)
	{
 	//son process read string
	
		close(fd[1]);//关闭写端
		n_read = read(fd[0],buf,128);//读管道消息
		printf("read:%d byte,content:%s\n",n_read,buf);
		exit(0);

	}else
	{
		printf( "creat fork failed\n");
		return -1;
	}	
	
	free(buf);
	return 0;
}

效果截图
在这里插入图片描述

有名管道

1.fifo_write.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
//int pipe(int fd[2]);    // 返回值:若成功返回0,失败返回-1

int main()
{
	
	int fd;
	int n_read;
	int n_write;
	char *buf = "you are a handsomeboy";
	//create fifo file
	printf("Please create file\n");
	if (mkfifo("./file",0600)== -1 && errno != EEXIST)
	{
		puts("mkfifo failed\n");
		return -1;
	}
	//open file
	fd = open("./file",O_WRONLY);
	if(fd == -1)
	{
		perror("why");
		return -1;
	}
	//write file
	while(1)
	{
		n_write = write(fd,buf,strlen(buf));
		sleep(1);
	}
	return 0;
}

2.fifo_read.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
//int pipe(int fd[2]);    // 返回值:若成功返回0,失败返回-1

int main()
{
	
	int fd;
	int n_read;
	char buf[1024] = {0};
	//create fifo file
	if( mkfifo("./file",0600) == -1 && errno != EEXIST)
	{
		puts("creat mkfifo failed\n");
		return -1;
	}
	//open file
	fd = open("./file",O_RDONLY);
	if(fd == -1)
	{
		perror("why");
		return -1;
	}
	//read file
	while(1)
	{
		n_read = read(fd,buf,1024);
		printf("read %d byte,content:%s\n",n_read,buf);
		sleep(2);	
	}

	return 0;
}

效果截图
在这里插入图片描述

二、消息队列

1.msg_snd.c

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

/*
   2 // 创建或打开消息队列:成功返回队列ID,失败返回-1
   3 int msgget(key_t key, int flag);

   4 // 发送消息:成功返回0,失败返回-1
   5 int msgsnd(int msqid, const void *ptr, size_t size, int flag);

   6 // 接收消息:成功返回消息数据的长度,失败返回-1
   7 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);

   8 // 控制消息队列:成功返回0,失败返回-1
   9 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
   */
struct Msg
{
	long mtype;
	char mtext[128];
};

int main()
{
	struct Msg sendbuf = { 888,"hello poorguy do you see me?" };
	key_t key;
	key = ftok(".",100);
	int msqid;
	int ret;
	int cnt = 5;
	msqid = msgget(key,IPC_CREAT|0777);
	if(msqid == -1)
	{
		printf("msgget failed\n");
		return -1;
	}

	while(1)
	{
		ret = msgsnd(msqid,&sendbuf,sizeof(sendbuf.mtext),888);
		if(ret == -1)
		{
			printf("recevied faile\n");
			return -1;
		}
		sleep(1);
	}
	/*
	   ret = msgrcv(msqid,&readbuf,sizeof(readbuf.mtext),888,0);
	   if(ret == -1)
	   {
	   printf("recevied faile\n");
	   return -1;
	   }
	*/
	
   	msgctl(msqid, IPC_RMID, NULL);

	return 0;
}

2.msg_rcv.c

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

/*
2 // 创建或打开消息队列:成功返回队列ID,失败返回-1
3 int msgget(key_t key, int flag);

4 // 发送消息:成功返回0,失败返回-1
5 int msgsnd(int msqid, const void *ptr, size_t size, int flag);

6 // 接收消息:成功返回消息数据的长度,失败返回-1
7 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);

8 // 控制消息队列:成功返回0,失败返回-1
9 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
*/
struct Msg
{
	long mtype;
	char mtext[128];
};
int main()
{
	struct Msg readbuf;
	key_t key;
	key = ftok(".",100);
	int msqid;
	int ret;
	int cnt = 5;
	msqid = msgget(key,IPC_CREAT|0777);
	if(msqid == -1)
	{
		printf("msgget failed\n");
		return -1;
	}

	while(1)
	{
		ret = msgrcv(msqid,&readbuf,sizeof(readbuf.mtext),888,0);
		if(ret == -1)
		{
			printf("recevied faile\n");
			return -1;
		}
		printf("From msgque content:%s\n",readbuf.mtext);
		sleep(1);
	}
	
	msgctl(msqid,IPC_RMID,NULL);
	return 0;
}

效果截图
在这里插入图片描述

三、共享内存

1.shm_write.c

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

/*
2 // 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
3 int shmget(key_t key, size_t size, int flag);

4 // 连接共享内存到当前进程的地址空间(也叫挂载、映射):成功返回指向共享内存的指针,失败返回-1
5 void *shmat(int shm_id, const void *addr, int flag);

6 // 断开与共享内存的连接:成功返回0,失败返回-1
//注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。
7 int shmdt(void *addr); 

8 // 控制共享内存的相关信息:成功返回0,失败返回-1
9 int shmctl(int shm_id, int cmd, struct shmid_ds *buf);           
*/
int main()
{

	int shm_id;
	key_t key = ftok(".",100);
	char *shm_addr;
	int shmdt_t;
	//创建获取共享内存shmget
	
	shm_id = shmget(key,1024*4,IPC_CREAT | 0600);
	if(shm_id == -1)
	{
		printf("creat shmget failed\n");
		return -1;
	}

	//连接共享内存shmat
	shm_addr = shmat(shm_id,0,0);
	

	//写数据存入共享内存shmmdt

	strcpy(shm_addr,"From share memory message: hello poorguy");

	sleep(10);

	//断开连接shmdt
	shmdt_t = shmdt(shm_addr);
	if( shmdt_t == -1 )
	{
		printf("close shmdt failed\n");
	}
	
	//销毁共享内存shmctl
	shmctl(shm_id,IPC_RMID,0);

	return 0;
}

2.shm_read.c

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

/*
2 // 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
3 int shmget(key_t key, size_t size, int flag);

4 // 连接共享内存到当前进程的地址空间(也叫挂载、映射):成功返回指向共享内存的指针,失败返回-1
5 void *shmat(int shm_id, const void *addr, int flag);

6 // 断开与共享内存的连接:成功返回0,失败返回-1
//注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。
7 int shmdt(void *addr); 

8 // 控制共享内存的相关信息:成功返回0,失败返回-1
9 int shmctl(int shm_id, int cmd, struct shmid_ds *buf);           
*/
int main()
{

	int shm_id;
	key_t key = ftok(".",100);
	char *shm_addr;
	int shmdt_t;
	//创建获取共享内存shmget
	
	shm_id = shmget(key,1024*4,IPC_CREAT | 0600);
	if(shm_id == -1)
	{
		printf("creat shmget failed\n");
			return -1;
	}

	//连接共享内存shmat
	shm_addr = shmat(shm_id,0,0);


	//从共享内存中读取数据

	printf("As follow:\n%s\n",shm_addr);

	//断开连接shmdt
	shmdt_t = shmdt(shm_addr);
	if( shmdt_t == -1 )
	{
		printf("close shmdt failed\n");
	}
	
	//销毁共享内存shmctl
	shmctl(shm_id,IPC_RMID,0);

	return 0;
}

效果截图在这里插入图片描述

四、信号

信号处理的三种方式:忽略,捕捉和默认动作。
忽略:就跟字面意思一样忽略掉它(注意:SIGKILL,SIGSTOP不能被忽略)
捕捉:就是一些信号处理的函数,然后让这个函数告诉内核,当信号产生时,内核调用该函数,实现某种信号的处理
默认动作:每个信号都有其对应的默认的处理动作,当触发了某种信号,系统就会立刻去执行。

1.捕捉ctr+c信号

signal.c

#include <signal.h>
#include <stdio.h>
//      typedef定义了一种类型sighandler_t
       //typedef void (*sighandler_t)(int);//函数指针(指向函数的指针),无返回值,传入参数为一个int型
       //sighandler_t signal(int signum, sighandler_t handler);
//     返回这种类型                   带有_t表示结构体  函数指针变量

void Handler(int signum)
{

	switch(signum)
	{

		case 2:		
			printf("receive SIGINT,signum = %d\n",signum);
			break;
		case 9:
			printf("receive SIGKILL,signum = %d\n",signum);
			break;
		case 20:
			printf("receive SIGUSR1,signum = %d\n",signum);
			break;
	}
	printf("never quit");

}


int main()
{
	
	signal(SIGINT,Handler);
	signal(SIGKILL,Handler);
	signal(SIGTSTP,Handler);
	while(1);
	return 0;
}

效果截图
在这里插入图片描述

2.给指定的进程发送信号(把该进程杀死SIGKILL)

signal2.c

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

//      typedef定义了一种类型sighandler_t
       //typedef void (*sighandler_t)(int);//函数指针(指向函数的指针),无返回值,传入参数为一个int型
       //sighandler_t signal(int signum, sighandler_t handler);
//     返回这种类型                   带有_t表示结构体  函数指针变量


int main(int argc,char **argv[])
{
	//三个参数kill -9 33550
	int signum;
	int pid;
	char cmd[128];
	signum = atoi(argv[1]);
	pid = atoi(argv[2]);

	//信号发送
	sprintf(cmd,"kill -%d %d",signum,pid);
	system(cmd);

	printf("发送指令信号成功\n");
	return 0;
}

3. 信号发送携带消息

收发信号
sig_send.c

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

/*struct sigaction 
{			   //凡是带有_t说明是个结构体
               void (*sa_handler)(int);//信号处理程序,不接受额外数据,和signal()的参数handler一样(SIG_IGN 为忽略,SIG_DFL 为默认动作)
               void     (*sa_sigaction)(int, siginfo_t *, void *);//信号处理程序,能够接受额外数据和sigqueue配合使用
               sigset_t   sa_mask;//阻塞关键字的信号集(默认阻塞),可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。
               int        sa_flags;//配置为SA_SIGINFO这个宏表示能够接受数据
               void     (*sa_restorer)(void);
};*/
/*union sigval 
{
               int   sival_int;
               void *sival_ptr;  发送字符的话把地址传进来
};*/
/*
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
//sigactio(),会依照参数signum指定的信号编号来设置该信号的处理函数
//const struct sigaction *act,你要做什么
//struct sigaction *oldact,是否备份,不备份用NULL
*/

int main(int argc,char *argv[])
{
	//信号类型/信号源
	int signum = atoi(argv[1]);
	int pid = atoi(argv[2]);

	//要发送的数据可以是整数也可以是字符
	union sigval value;
	value.sival_int = 67;

	//发送消息函数sigqueue
	
	sigqueue(pid,signum,value);

	printf("my_pid = %d\n",getpid());

	printf("发送完毕\n");
	return 0;
}


sig_rcv.c

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

/*struct sigaction 
{			   //凡是带有_t说明是个结构体
               void (*sa_handler)(int);//信号处理程序,不接受额外数据,和signal()的参数handler一样(SIG_IGN 为忽略,SIG_DFL 为默认动作)
               void     (*sa_sigaction)(int, siginfo_t *, void *);//信号处理程序,能够接受额外数据和sigqueue配合使用
               sigset_t   sa_mask;//阻塞关键字的信号集(默认阻塞),可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。
               int        sa_flags;//配置为SA_SIGINFO这个宏表示能够接受数据
               void     (*sa_restorer)(void);
};*/
/*union sigval 
{
               int   sival_int;
               void *sival_ptr;  发送字符的话把地址传进来
};*/
/*
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
//sigactio(),会依照参数signum指定的信号编号来设置该信号的处理函数
//const struct sigaction *act,你要做什么
//struct sigaction *oldact,是否备份,不备份用NULL
*/
void handler(int signum, siginfo_t *info, void * context)
{

		printf("signum = %d\n",signum);
		if( context != NULL )
		{
			printf("信号源pid = %d\n",info->si_pid);
			printf("get data: %d\n",info->si_int);
			printf("get data: %d\n",info->si_value.sival_int);
			
		}

}

int main(int argc,char *argv[])
{
	struct sigaction act;
	printf("my_pid=%d\n",getpid());
	
	act.sa_sigaction = handler;
	act.sa_flags = SA_SIGINFO;//能够获取到信息的标志
	//接收数据
	
	sigaction(SIGUSR1,&act,NULL);//第三个是参数是备份的这边写NULL SIGUSR1对应的编号为10!!!SIGUSR1为用户自定义信号,

	while(1);
	return 0;
}

效果截图
在这里插入图片描述

五、信号量

函数解析
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

信号量编程代码如下:

sem_pv.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <unistd.h>

 /*
2 // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
3 int semget(key_t key, int num_sems, int sem_flags);
4 // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
5 int semop(int semid, struct sembuf semoparray[], size_t numops);  
6 // 控制信号量的相关信息
7 int semctl(int semid, int sem_num, int cmd, ...);
*/

//semctl函数第三个参数cmd的宏要求后面定义一个联合体
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) */
};

void pGetKey(int sem_id)//P操作(拿锁)
{
    struct sembuf sem_set;
    sem_set.sem_num = 0;//信号量编号,每把钥匙都有特点编号,这里只有一把锁(也就是第一个信号量)
    sem_set.sem_op = -1;//拿锁(-1表示P操作)
    sem_set.sem_flg = SEM_UNDO; //SEM_UNDO设置为当进程结束的时候,系统自动释放该进程未释放的信号量

    //进行PV操作
    semop(sem_id,&sem_set,1);//“1”代表第二个参数的个数

    printf("锁被拿\n");
}
void vPutBackKey(int sem_id)//v操作(放回钥匙)
{
    struct sembuf sem_set;
    sem_set.sem_num = 0;
    sem_set.sem_op = 1;//(1表示P操作)
    sem_set.sem_flg = SEM_UNDO;//进程结束,释放信号量

    //进行PV操作
    semop(sem_id,&sem_set,1);
	printf("已放回锁\n");
}


int main()
{

    key_t key = ftok(".",2);
    int sem_id;
    int pid;
    
    union semun init_sem;
    init_sem.val = 0;//初始是没有钥匙的状态
    //1.创建信号量组
    sem_id = semget(key,1,IPC_CREAT|0666 );

    //2.控制信号量的相关信息
    //int semctl(int semid, int sem_num, int cmd, ...);
    semctl(sem_id,0,SETVAL,init_sem);

    //3.执行操作(拿锁放锁操作)
    pid = fork();
    
    if(pid > 0)//父进程“拿锁”,拿锁之后放锁
    {

        pGetKey(sem_id);//开锁
        
        printf("我是父进程,我要拿锁进房间\n");
        vPutBackKey(sem_id);//开锁之后把钥匙放回去

        semctl(sem_id,0,IPC_RMID);//销毁这个锁
    }else if(pid == 0)//子进程放锁,不拿锁
    {
        printf("我是子进程,我要把锁放回盒子\n");
        vPutBackKey(sem_id);
    }else
    {
        printf("fork error\n");
    }
    
    return 0;
}

效果截图
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值