Linux多线程编程—进程间通信

一.匿名管道

(1) int pipe(int pipefd[2]);
功能:创建管道 将读端的文件描述符返回到pipefd[0] 将写端文件描述符返回到pipefd[1]
返回值:成功0 失败-1

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
	int fd[2];
	int ret = pipe(fd);
	if(ret<0)
	{
		perror("pipe");
		exit(-1);
	}
	printf("ceat suc  fd[0]:%d  fd[1]:%d\n",fd[0],fd[1]);
	return 0;
}
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
	int fd[2];
	int ret = pipe(fd);
	if(ret<0)
	{
		perror("pipe");
		exit(-1);
	}
	size_t ret2 = write(fd[1],"hungry",7);
	if(ret2<0)
	{
		perror("write");
	}
	char buf[100]="\0";
	size_t ret1 = read(fd[0],buf,sizeof(buf));
	if(ret1<0)
	{
		perror("read");
		exit(-1);
	}
	printf("read:%s\n",buf);
	return 0;
}

(2)注意:
a、管道中的数据读完就删除 再读 读操作阻塞
b、管道写满 会写阻塞
c、进程结束后 管道文件不存在
d、只能用于亲属关系进程
e、半双工

父子进程间通信:

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

int main()
{
	int fd[2];
	int ret = pipe(fd);
	if(ret<0)
	{
		perror("pipe");
		exit(-1);
	}

	pid_t pid = fork();
	if(pid>0)
	{
		close(fd[1]);
		int m;
		read(fd[0],&m,sizeof(m));
		printf("%d\n",m);
	}
	else if(pid==0)
	{
		close(fd[0]);
		int n=100;
		write(fd[1],&n,sizeof(n));
	}
	else 
	{
		perror("fork");
	}
	return 0;
}

练习:父进程从键盘从获取字符串 发送给子进程 子进程获取字符串后 将其转为大写 并输出

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
void change(char *p)
{
	while(*p)
	{
		if(*p>='a'&&*p<='z')
		{
			*p -= 32;
		}
		p++;
	}
}
int main()
{
	int fd[2];
	int ret = pipe(fd);
	if(ret<0)
	{
		perror("pipe");
		exit(-1);
	}

	pid_t pid = fork();
	if(pid>0)
	{
		char str[1024]="\0";
		puts("please input a string:");
		scanf("%s",str);
		ssize_t ret = write(fd[1],str,sizeof(str));
		if(ret<0)
		{
			perror("write");
			exit(-1);
		}
	}
	else if(pid==0)
	{
		char string[1024]="\0";
		ssize_t ret  = read(fd[0],string,sizeof(string));
		if(ret<0)
		{
			perror("write");
			exit(-1);
		}
		change(string);
		printf("%s\n",string);
	}
	else 
	{
		perror("fork");
	}
	return 0;
}

二.有名管道:亲属 非亲属

 (1)int mkfifo(const char *pathname, mode_t mode);
	功能:按指定的权限创建管道文件
	参数1:要创建的管道 
	参数2:同open 参数3  指定要创建的管道的操作权限
	返回值:成功0 失败-1
#include<sys/stat.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
	int ret = mkfifo("myfifo",0777);
	if(ret<0)
	{
		perror("mkfifo");
		exit(-1);
	}
	return 0;
}
#include<sys/stat.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
	int fd = open("myfifo",O_WRONLY);
	if(fd<0)
	{
		perror("open");
		exit(-1);
	}
	puts("open after..............");
	char buf[]="good good study";
	ssize_t ret = write(fd,buf,sizeof(buf));
	if(ret<0)
	{
		perror("write");
		exit(-1);
	}
	return 0;

}
#include<sys/stat.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
	int fd = open("myfifo",O_RDONLY);
	if(fd<0)
	{
		perror("open");
		exit(-1);
	}
	char buf[1024]="\0";
	ssize_t ret = read(fd,buf,sizeof(buf));
	if(ret<0)
	{
		perror("read");
		exit(-1);
	}
	puts("read after.....");
	puts(buf);
	return 0;
}

练习:进程a从键盘获取字符串发送给进程b 进程b获取后转为大写 输出

#include<stdlib.h>
#include<unistd.h>

int main()
{
	int ret#include<sys/stat.h>
#include<stdio.h>
 = mkfifo("myfifo",0777);
	if(ret<0)
	{
		perror("mkfifo");
		exit(-1);
	}
	return 0;

}
#include<sys/stat.h>
	#include<stdio.h>
	#include<stdlib.h>
	#include<unistd.h>
	#include<sys/types.h>
	#include<fcntl.h>
	int main()
	{
		int fd = open("myfifo",O_WRONLY);
		if(fd<0)
		{
			perror("open");
			exit(-1);
		}

		char str[1024];
		puts("input a string:");
		gets(str);
		ssize_t ret = write(fd,str,sizeof(str));
		if(ret<0)
		{
			perror("write");
			exit(-1);
		}
		return 0;

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

void change(char *p)
{
	while(*p)
	{
		if(*p>='a'&&*p<='z')
		{
			*p -= 32;
		}
		p++;
	}
}
int main()
{
	int fd = open("myfifo",O_RDONLY);
	if(fd<0)
	{
		perror("open");
		exit(-1);
	}
	char buf[1024]="\0";
	ssize_t ret = read(fd,buf,sizeof(buf));
	if(ret<0)
	{
		perror("read");
		exit(-1);
	}
	change(buf);
	puts(buf);
	return 0;
}

练习:进程a从标准输入获取一个人信息(姓名 年龄 体重) 发送给进程b 进程b输出读到的数据

#include"my.h"
int main()
{
	int ret = mkfifo("myfifo",0777);
	if(ret<0)
	{
		perror("mkfifo");
		exit(-1);
	}
	return 0;
}
#include"my.h"
int main()
{
	int fd = open("myfifo",O_WRONLY);
	if(fd<0)
	{
		perror("open");
		exit(-1);
	}
	person_t x;
	puts("input name age weight:");
	scanf("%s%d%lf",x.name,&x.age,&x.weight);
	ssize_t ret = write(fd,&x,sizeof(x));
	if(ret<0)
	{
		perror("write");
		exit(-1);
	}
	return 0;
}
#include"my.h"
int main()
{
	int fd = open("myfifo",O_RDONLY);
	if(fd<0)
	{
		perror("open");
		exit(-1);
	}
	person_t y;
	ssize_t ret = read(fd,&y,sizeof(y));
	if(ret<0)
	{
		perror("read");
		exit(-1);
	}
	printf("name:%s age:%d weight:%lf\n",y.name,y.age,y.weight);
	return 0;

}

三.信号

1.查看信号列表 kill -l
2.
SIGINT ctrl+c发出的信号
SIGQUIT ctrl+\ 发出的信号 终止程序
SIGILL 非法指令
SIGABRT 通过函数abort()发出的信号 实现程序终止
SIGFPE 浮点异常 除数为0
SIGKILL 必杀信号
SIGPIPE 管道破裂
SIGSEGV 段错误
SIGALRM 通过alarm()发出的信号
SIGTERM 终止信号 kill命令发出的信号
SIGCHLD 子进程停止或终止
SIGCONT 使一个暂停(停止)的进程继续
SIGSTOP 使进程暂停
SIGTSTP ctrl+z发出的信号
3.
信号发送 kill alarm raise
信号接收 while(1) sleep(100000) pause()
信号处理 signal() 默认 忽略 捕捉

(1)signal(信号编号,信号处理方式)
功能:告诉内核 当信号到来时 如何处理信号 —注册信号
信号处理方式3中:
默认 SIG_DFL
忽略 SIG_IGN
捕捉 信号处理函数 处理函数要求:返回值必须为void 形参必须为int
练习1:当用户输入ctrl+\ 会发出SIGQUIT 写程序捕捉这个信号 并打印信号的值

#include"my.h"
void sig_fun(int sig)
{
	puts("就不退出.....");
	printf("%d\n",sig);//信号编号
}
int main()
{
	//signal(SIGINT,SIG_DFL);//默认
	//signal(SIGINT,SIG_IGN);//忽略
	signal(SIGINT,sig_fun);//告诉内核 当信号SIGINT到来时  调用sig_fun函数
	while(1);//保证进程不消亡
	return 0;
}

练习2:向数组中赋值 当收到信号SIGINT时

 #include"my.h"
#define N 1024
int count;
void sig_fun(int sig)
{
	printf("%d\n",count);
}
int main()
{
	int arr[N];
	int i;
	signal(SIGINT,sig_fun);//告诉内核 当信号SIGINT到来时  调用sig_fun函数

	for(i=0;i<N;i++)
	{
		arr[i]=i+1;
		count++;
		sleep(1);
	}
	while(1);//保证进程不消亡
	return 0;
}

(2)信号接收
#include <unistd.h>
int pause(void);
功能:使当前进程暂停 直到被信号中断

   #include"my.h"
void fun(int s)
{
	puts("ha~ha~ha~");
}
int main()
{
	signal(SIGINT,fun);
	puts("before pause ");
	pause();
	puts("after pause");
}          

(3)信号发送
#include <sys/types.h>
#include <signal.h>

1)int kill(pid_t pid, int sig);
功能:向pid进程发送信号sig
返回值:成功0 失败-1

练习:有两个进程 一个进程接收信号SIGINT 收到信号后 将信号编号打印
另一个进程负责发送SIGINT给接收进程

要求:第二个进程 进程PID 及信号 不写固定值 (int main(argc,char*argv[]))
./a.out pid 2

atoi()

//while.c

	#include"my.h"
void deal_fun(int sig)
{
	printf("%d\n",sig);
}
int main(int argc,char*argv[])
{
	if(argc!=2)
	{
		printf("%s signal\n",argv[0]);
		exit(-1);
	}
	int sig = atoi(argv[1]);
	signal(sig,deal_fun);
	printf("%d\n",getpid());
	pause();
}

//kill.c

#include"my.h"
int main(int argc,char*argv[])
{
	if(argc!=3)
	{
		printf("%s pid sig\n",argv[0]);
		exit(-1);
	}

	int sig = atoi(argv[2]);
	int pid = atoi(argv[1]);

	int ret = kill(pid,sig);
	if(ret<0)
	{
		perror("kill");
		exit(-1);
	}
}   

2)alarm
unsigned int alarm(unsigned int seconds);
功能:定时 经过指定秒数 系统会自动向本进程发送SIGALRM

 #include"my.h"
void sig_fun(int sig)
{
	puts("wake up....");
}
int main()
{
	signal(SIGALRM,sig_fun);

	alarm(3);//3秒后 内核会向本进程发送SIGALRM 
	while(1);
}

3)raise
int raise(int sig);
功能:发信号给本进程

#include"my.h"
int main()
{
	raise(9);//向本进程发送信号SIGKILL
	while(1)
	{
		puts("**************");
		sleep(1);
	}
}

练习:每隔1s 打印出系统时间 alarm实现

#include"my.h"
void sig_fun(int sig)
{
	time_t t=time(NULL);
	printf("%s",ctime(&t));

	alarm(1);

}
int main()
{
	signal(SIGALRM,sig_fun);
	alarm(1);
	while(1);
}

练习:字母游戏
获取随机字母
键盘输入
匹配
闹铃时间到 统计出1分钟匹配多少个字母

#include"my.h"
int count;
void sig_fun(int sig)
{
	printf("%d\n",count*4);
}
int main()
{
	char ch,my_ch;
	srand(time(NULL));
	signal(SIGALRM,sig_fun);
	alarm(15);
	printf("\nHave Fun Time!\n");
	while(1)
	{
		ch = rand()%26+'a';
		printf("%c\n",ch);
		my_ch = getchar();
		getchar();
		if(ch==my_ch)
		{
			count++;
		}
	}
	return 0;
}

练习:编写程序 创建一个子进程
父进程捕捉信号SIGINT(ctrl+c发 也可以kill命令发)
父进程当捕捉到中断信号后 向子进程发出信号
子进程捕捉到父进程发来的信号 输出:child process is killed by parent!
父进程等待子进程终止后 输出:Parent process exit!

#include"my.h"
pid_t pid;
void sig_fun_father(int s)
{
	puts("father catch sigint....");
	kill(pid,SIGALRM);
}
void sig_fun_child(int s)
{
	puts("child is killed by father!");
	exit(0);
}
int main()
{
	 pid = fork();
	if(pid<0)
	{
		perror("fork");
	}
	else if(pid>0)//父亲
	{
		signal(SIGINT,sig_fun_father);
		printf("father pid:%d\n",getpid());	
		wait(NULL);
		puts("father exit!");
	}
	else //子
	{
		signal(SIGINT,SIG_IGN);
		signal(SIGALRM,sig_fun_child);
		sleep(1);
		printf("child....pid:%d\n",getpid());
		while(1);
	}
}
#include"my.h"
void fun(int sig)
{
	switch(sig)
	{
		case SIGINT:
			puts("不怕CTRL+C");
			break;
		case SIGQUIT:
			puts("就不退出 ");
			break;
		case SIGTSTP:
			puts("我是不会停止滴");
			break;
	}
}
int main()
{
	signal(SIGINT,fun);
	signal(SIGQUIT,fun);
	signal(SIGTSTP,fun);
	while(1);
}

四. 共享内存

共享内存是所有进程间通信方式中效率最高的 最快
步骤:
 创建共享内存对象
 映射共享内存
 对共享内存读写
 解除映射
 删除共享内存对象

  1. int shmget(key_t key, size_t size, int shmflg);
    功能:创建或打开一个共享内存对象
    参数1:标准共享内存 可以是ftok返回值 也可以是IPC_PRIVATE
    参数2:新创建的共享内存大小 如果是0 表示取得共享内存对象
    参数3:0 表示取得共享内存对象 IPC_CREAT 表示不存在 就创建 IPC_CREAT|0777
    返回值:成功返回共享内存标识符 出错-1

ipcs -m 查看共享对象
ipcrm -m shmid 删除共享内存对象

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

int main()
{
	int shmid = shmget(IPC_PRIVATE,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		perror("shmget");
		exit(-1);
	}

	printf("shmid:%d\n",shmid);
	return 0;
}
  1. key_t ftok(const char *pathname, int proj_id);
    功能:成功调用会返回一个key值 失败-1
    参数1:文件名包含路径 注意:必须已经存在
    参数2:一个整数
    返回值:成功返回唯一key值 失败-1
#include<stdlib.h>
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
int main()
{
	key_t key = ftok("/home/linux",'a');//
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	int shmid = shmget(key,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		perror("shmget");
		exit(-1);
	}

	printf("shmid:%d\n",shmid);
	return 0;
}
  1. void *shmat(int shmid, const void shmaddr, int shmflg);
    功能:将共享内存对象映射到用户空间地址中
    参数1:映射的是哪块内存
    参数2:映射到用户空间的哪块地址 传NULL 表示系统自动选地址
    参数3:0 表示共享内存可读写 SHM_RDONLY 共享内存只读
    返回值:成功返回映射后的地址 失败(void
    )-1
  2. int shmdt(const void *shmaddr);
    功能:解除映射
  3. shmctl
    删除共享内存对象 shmctl(shmid,IPC_RMID,NULL)
    //write.c
#include"../my.h"
int main()
{
	key_t key = ftok("/home/linux",'a');//
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	int shmid = shmget(key,0,0);
	if(shmid<0)
	{
		perror("shmget");
		exit(-1);
	}

	int *p = shmat(shmid,NULL,0);
	if(p==(void*)-1)
	{
		perror("shmdt");
		exit(-1);
	}

	*p = 100;

	shmdt(p);
}

//read.c

#include"../my.h"
int main()
{
	key_t key = ftok("/home/linux",'a');//
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	int shmid = shmget(key,0,0);
	if(shmid<0)
	{
		perror("shmget");
		exit(-1);
	}

	int *p = shmat(shmid,NULL,SHM_RDONLY);	
	if(p==(void*)-1)
	{
		perror("shmat");
		exit(-1);
	}

	printf("%d\n",*p);

	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);
}

练习:进程a发送字符串给进程b 进程b将其转为大写 输出

//creat.c

#include<stdlib.h>
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
int main()
{
	key_t key = ftok("/home/linux",'a');//
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	int shmid = shmget(key,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		perror("shmget");
		exit(-1);
	}

	printf("shmid:%d\n",shmid);
	return 0;
}

//write.c

#include"../my.h"

int main()
{
	key_t key = ftok("/home/linux",'a');//
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	int shmid = shmget(key,0,0);
	if(shmid<0)
	{
		perror("shmget");
		exit(-1);
	}

	char *p = shmat(shmid,NULL,0);
	if(p==(void*)-1)
	{
		perror("shmdt");
		exit(-1);
	}
	puts("input string:");
	gets(p);
	shmdt(p);
}

//read.c

#include"../my.h"

void changet(char *p)
{
	while(*p)
	{
		if(*p>='a'&&*p<='z')
		{
			*p -= 32;
		}

		p++;
	}
}
int main()
{
	key_t key = ftok("/home/linux",'a');//
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	int shmid = shmget(key,0,0);
	if(shmid<0)
	{
		perror("shmget");
		exit(-1);
	}

	char *p = shmat(shmid,NULL,0);	
	if(p==(void*)-1)
	{
		perror("shmat");
		exit(-1);
	}
	changet(p);
	printf("%s\n",p);

	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);
}

练习2:
一个进程将数据写入共享内存后 用信号通知另一个进程
另一个进程捕捉到信号后 将信息打印出来

//write.c

#include"../my.h"

int main(int argc,char*argv[])
{
	if(argc!=2)
	{
		printf("%s pid\n",argv[0]);
		exit(-1);
	}
	key_t key = ftok("/home/linux",'a');//
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	int shmid = shmget(key,0,0);
	if(shmid<0)
	{
		perror("shmget");
		exit(-1);
	}

	char *p = shmat(shmid,NULL,0);
	if(p==(void*)-1)
	{
		perror("shmdt");
		exit(-1);
	}

	pid_t pid = atoi(argv[1]);
	while(1)
	{
		puts("input string:");
		gets(p);
		kill(pid,SIGUSR1);
	}
}

//read.c

#include"../my.h"
char *p;
void sig_fun(int sig)
{
	printf("%s\n",p);
}
int main()
{
	signal(SIGUSR1,sig_fun);
	printf("%d\n",getpid());
	key_t key = ftok("/home/linux",'a');//
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	int shmid = shmget(key,0,0);
	if(shmid<0)
	{
		perror("shmget");
		exit(-1);
	}

	p = shmat(shmid,NULL,0);	
	if(p==(void*)-1)
	{
		perror("shmat");
		exit(-1);
	}

	while(1)
	{
		;
	}
}

五.消息队列

  1. int msgget(key_t key, int msgflg);
       功能:创建或打开一个消息队列
       参数1:同上
       参数2:消息队列的访问权限及打开方式    IPC_CREAT|O_RDONLY
       返回值:成功返回消息队列标识符 失败-1
    ipcs -q 查看消息队列对象
    ipcrm -q msgid 删除消息队列对象
#include"../my.h"
int main()
{
	key_t key = ftok("/home",'b');
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	int msgid = msgget(key,IPC_CREAT|0777);
	if(msgid<0)
	{
		perror("msgget");
		exit(-1);
	}
	printf("msgid:%d\n",msgid);
	return 0;
}
  1. int msgsnd(int msqid, const void msgp, size_t msgsz, int msgflg);
    功能:将msgp里消息写入msgqid的消息队列
    参数2:
    struct msgbuf {
    long mtype; /
    message type, must be > 0 /消息类型 必须>0
    char mtext[1]; /
    message data */消息
    };
    参数3:消息大小 注意!!!:不包括消息类型的大小
    参数4: 如果是0 表示消息队列满时 msgsnd会阻塞 如果IPC_NOWAIT 不阻塞
    返回值:成功0 失败-1
#include"../my.h"
struct mymsg
{
	long type;
	int n;
};
int main()
{
	key_t key = ftok("/home",'b');
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	struct mymsg m;
	m.n = 100;
	m.type = 1;
	int msgid = msgget(key,O_WRONLY);
	if(msgid<0)
	{
		perror("msgget");
		exit(-1);
	}

	int ret = msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0);
	if(ret<0)
	{
		perror("msgsnd");
		exit(-1);
	}

}		   
  1. ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
    功能:按类型接收消息
    参数2:存放消息缓存
    参数3:收到的消息的大小 注意:不包括类型大小
    参数4:按msgtyp的类型接收消息 如果传0 表示接收任意类型消息
    参数5:如果是0 表示没有指定类型的消息 msgrcv会阻塞 如果设置成IPC_NOWAIT 表示不阻塞

//write.c

#include"../my.h"
struct mymsg
{
	long type;
	int n;
};
int main()
{
	key_t key = ftok("/home",'b');
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	struct mymsg m;
	puts("input data type");
	scanf("%d%ld",&m.n,&m.type);
	int msgid = msgget(key,O_WRONLY);
	if(msgid<0)
	{
		perror("msgget");
		exit(-1);
	}

	int ret = msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0);
	if(ret<0)
	{
		perror("msgsnd");
		exit(-1);
	}

}

//read.c

#include"../my.h"
struct mymsg
{
	long type;
	int n;
};
int main()
{
	key_t key = ftok("/home",'b');
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	struct mymsg m;
	puts("input type:");
	scanf("%ld",&m.type);
	int msgid = msgget(key,O_RDONLY);
	if(msgid<0)
	{
		perror("msgget");
		exit(-1);
	}

	ssize_t ret = msgrcv(msgid,&m,sizeof(m)-sizeof(m.type),m.type,0);
	if(ret<0)
	{
		perror("msgrcv");
		exit(-1);
	}
	printf("%d\n",m.n);
}

练习:进程a发送字符串给进程b 进程b将其转为大写 输出
//write.c

#include"../my.h"
struct mymsg
{
	long type;
	char data[1024];
};
int main()
{
	key_t key = ftok("/home",'b');
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	struct mymsg m;
	puts("input data type");
	scanf("%s%ld",m.data,&m.type);
	int msgid = msgget(key,O_WRONLY);
	if(msgid<0)
	{
		perror("msgget");
		exit(-1);
	}

	int ret = msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0);
	if(ret<0)
	{
		perror("msgsnd");
		exit(-1);
	}

}

//read.c

#include"../my.h"
struct mymsg
{
	long type;
	char data[1024];
};

void change(char *p)
{
	while(*p)
	{
		if(*p>='a'&&*p<='z')
		{
			*p -= 32;
		}
		p++;
	}
}
int main()
{
	key_t key = ftok("/home",'b');
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	struct mymsg m;
	puts("input type:");
	scanf("%ld",&m.type);
	int msgid = msgget(key,O_RDONLY);
	if(msgid<0)
	{
		perror("msgget");
		exit(-1);
	}

	ssize_t ret = msgrcv(msgid,&m,sizeof(m)-sizeof(m.type),m.type,0);
	if(ret<0)
	{
		perror("msgrcv");
		exit(-1);
	}
	change(m.data);
	printf("%s\n",m.data);
}

练习:进程a发送学生信息 姓名 年龄 id 进程b收到后 输出
//write.c

#include"../my.h"
struct mymsg
{
	long type;
	char name[20];
	int age;
	int id;
};
int main()
{
	key_t key = ftok("/home",'b');
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	struct mymsg m;
	puts("input name age id  type");
	scanf("%s%d%d%ld",m.name,&m.age,&m.id,&m.type);
	int msgid = msgget(key,O_WRONLY);
	if(msgid<0)
	{
		perror("msgget");
		exit(-1);
	}

	int ret = msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0);
	if(ret<0)
	{
		perror("msgsnd");
		exit(-1);
	}

}

//read.c

#include"../my.h"
struct mymsg
{
	long type;
	char name[20];
	int age;
	int id;
};

int main()
{
	key_t key = ftok("/home",'b');
	if(key<0)
	{
		perror("ftok");
		exit(-1);
	}

	struct mymsg m;
	puts("input type:");
	scanf("%ld",&m.type);
	int msgid = msgget(key,O_RDONLY);
	if(msgid<0)
	{
		perror("msgget");
		exit(-1);
	}

	ssize_t ret = msgrcv(msgid,&m,sizeof(m)-sizeof(m.type),m.type,0);
	if(ret<0)
	{
		perror("msgrcv");
		exit(-1);
	}
	printf("name:%s age:%d id:%d\n",m.name,m.age,m.id);
}
  1. msgctl
    获取和设置消息队列的属性
    格式:msgctl(msgqid,IPC_RMID,NULL)

六.信号量

信号灯:协调进程同步手段 进程异步

  1. int semget(key_t key, int nsems, int semflg);
    功能:创建或取得信号量集对象
    参数1:同上
    参数2:信号量的个数 一般是1
    参数3:可以是0 也可以是IPC_CREAT|0777
    返回值:成功返回信号量集对象 失败-1

ipcs -s 查看信号量对象
ipcrm -s semid 删除信号量对象

#include"../my.h"
int main()
{
	key_t key = ftok("/home",'a');

	int semid = semget(key,1,IPC_CREAT|0777);
	if(semid<0)
	{
		perror("semget");
		exit(-1);
	}

	printf("semdi:%d\n",semid);
	return 0;

}
  1. int semop(int semid, struct sembuf *sops, unsigned nsops);
    功能:对信号量集semid进行sops指定的操作
    参数2:
struct sembuf{
	unsigned short sem_num;  /* semaphore number */信号量的编号 一般是0  表示第一个信号量
   	short          sem_op;   /* semaphore operation */信号量操作   +1 1     -1 
   	short          sem_flg;  /* operation flags */如果信号量为负数时 阻塞还是不阻塞 一般是0 表示阻塞
}

参数3:参数2中元素的个数 一般是1
3. semctl
设置信号量的值 semctl(semid,0,SETVAL,3)//设置semid集中 编号为0的信号量值为3

#include"../my.h"
int main()
{
	key_t key = ftok("/home",'a');
	int semid = semget(key,1,IPC_CREAT|0777);
	if(semid<0)
	{
		perror("semget");
		exit(-1);
	}
	semctl(semid,0,SETVAL,0);
	pid_t pid = fork();
	if(pid>0)
	{
		sleep(10);
		puts("i am father!");
		struct sembuf s;
		s.sem_num = 0;
		s.sem_op = 1;
		s.sem_flg = 0;
		semop(semid,&s,1);
		puts("father end!");
	}
	else if(pid==0)
	{
		struct sembuf s;
		s.sem_num = 0;
		s.sem_op = -1;
		s.sem_flg = 0;
		semop(semid,&s,1);
		puts("i am child!");
	}
	semctl(semid,0,IPC_RMID,NULL);//删除信号量集合semid中 编号为0的信号量
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值