C语言是一种面向过程的计算机程序设计语言。最初为unix而生。它既有高级语言的特点

源代码在线查看: 3.进程间通信(ipc).txt

软件大小: 262 K
上传用户: lwp
关键词: unix C语言 过程 计算机
下载地址: 免注册下载 普通下载 VIP

相关代码

				3.进程间通信(IPC)
				
				信号机制
				
				信号是一中异步事件(也称软中断),可通过信号机构停止一个程序。
				一个信号必定有他的发送者,接收者。一个信号的意义必须事先定义。
				信号表是把信号和信号处理函数一一对应的一个表结构,Unix定义了37种信号。
				
				注意:信号会打断任何的系统阻塞。
				
				信号的处理
				
				信号的处理有三种,忽略,捕获,默认方式(default)。
				信号的处理多用捕获和默认方式来处理。
				捕获是通过自定义的函数去替换信号表中的默认函数。
				
				几种重要的信号
				
				SIGALRM,超时信号(alram函数设置时钟到时后的发出的信号)
				SIGCHLD,当子进程中止时调用,此信号会发送给子进程的父进程,父进程会回收子进程资源,而不必等待子进程结束,可以运行自身的代码,这也就达到了异步运行的目的。(常用信号)
				SIGINT,此信号用于中止失控程序(按ctrl+c组合和delete键会发送此信号)
				SIGKILL,强制杀死进程的信号,此信号不能互略和捕获,只能按系统默认方式处理。
				SIGSTOP,作业控制信号,可以停止一个进程,此信号之能按系统默认方式处理。
				SIGUSR1,SIGUSR2,这两个是系统留给用户自定义的信号,一般多使用两个信号,并进行捕获处理。
				
				其余信号参见课本
				system()函数创建到子进程会忽略SIGINT,SIGQUIT两种信号。
				
				signal函数
				
				signal函数,是用来修改信号表中信号对应的处理函数。
				
				typedef void(*FUNC)(int)定义函数指针,int参数带表的是实际收到的信号。
				FUNC signal(int signo,FUNC fp)信号注册函数,
				signal函数的返回值是原来的信号处理函数。
				signo参数要是用信号的名字。(信号名本身是定义好的宏)
				
				注意:signal函数在实际使用时,只需要传入自定的函数名即可。自定义的信号处理函数需要特定的结构
				即void 函数名(int)。当信号接收后会调用相应的信号处理函数,也就是注册了的自定义函数。
				
				注意:Unix中会有信号丢失处理,signal函数只是注册后运行结束前有效。注册一次后,就只有这一次有效,所以可以在自定的信号捕获函数中递归的调用signal函数,这样可以避免信号丢失。也就使在信号处理函数中再调用signal函数注册这个信号处理函数。
				
				SIG_ERR捕获信号失败,SIG_DFL系统默认行为,SIG_IGN忽略信号,这些可以做signal函数的参数值也是返回值,可以判断信号是否捕获成功,或者是自定义信号处理函数是否注册成功。
				
				注意:在Unix中所有阻塞函数都会被信号打断。
				
				kill命令和kill函数
				
				kill,命令 kill -sig pid(进程id)可向任意进程发出信号。
				sig,去掉信号名前的SIG三个字母后信号的名字
				注意:这里的参数sig,就是去掉信号名前的SIG三个字母。
				
				kill函数
				
				int kill(pid_t pid,int sig),用于在程序中向任意进程发出信号。pid是进程id。sig是信号的全名。
				
				信号的自举
				int raise(int sig),程序本身自己向自己发信号,sig是信号的全名。
				
				alarm函数
				
				unsigned alarm(unsigned int sec)
				sec是指定的时间。
				这个函数的功能是从现在起的设定的时间间隔后发出一个SIGALRM信号。SIGALRM,信号的默认处理是进程中止退出。我们可以通过重新注册信号处理函数来实现相应功能。
				sec是时间间隔的描述。
				
				pause函数
				
				int pause()永久阻塞函数,直到信号打断后才会结束阻塞。
				
				sleep函数
				
				unsigned sleep(unsigned int sec)是进程进入睡眠状态制定的时间。
				sec是指定的时间。
				sleep函数在被打断后会返回没有睡够的秒数。
				
				Daemon进程
				
				父进程和子进程的进程组id相同,会话包含多个进程组。
				Daemon进程是在终端关闭后不会结束的进程。
				Daemon进程的父进程的id是1,也就是intit进程。他的进程组的id和会话的id是相同的,就是他本身,不使用控制终端。
				//父进程id为1
				pid_t=fork();
				if(pid>0)exit();
				//进程组id和会话id为本身
				setsid();
				//设置屏蔽字
				umask(0);
				for(int i=0;i					close(i);
				}
				以上是Daemon进程的标准写法
				
				FIFO管道文件
				
				使用FIFO时要包含两个头文件。
				
				mkfifo 文件名,创建管道文件命令。
				int mkfifo(const char* pathname,mode_t mode)创建管道文件。
				pathname是管道文件的文件名,mode是文件的权限。
				mkfifo函数的返回值表示FIFO文件创建是否成功,不是文件描述符。
				使用FIFO的条件
				(1)必须是两个进程同时对FIFO类型文件进行操作,并分别以只读和只写的方式才能打开FIFO文件,否则open函数会阻塞。
				(2)read()函数的返回值为0表示文件读取完毕,表示写入方关闭了FIFO文件。
				(3)FIFO文件在读取之后会自动清空,FIFO文件事先写入后读取,可以用于多进程间的通信。
				
				Message Queue(消息队列)
				
				注意:使用消息队列需要包含三个头文件。
				
				消息队列,实质上是一个由内核维护的消息链表,是用msqid作为消息队列的唯一标识。可以用ipcs来查询消息队列。用ipcrm 消息队列id,删除消息队列。
				
				消息队列的操作
				
				创建消息队列
				
				int msgget(key_t key,int flag)创建消息队列。
				参数key也是用以标识消息队列的值,key一般定义在头文件中。(可以用IPC_PRIVATE随机生成key)
				注意:key是在创建时用于查找相应的key值,如果查找到key值相同的消息队列就不创建新的队列了,而是使用这个队列,如果没有就会去查第二个参数,如果标识为新建会创建一个消息队列,如果不是会出错
				
				flag是一个标记,一般在创建时写成 (IPC_CREATE|权限)(权限设置和文件相同),如果置为0就会用key去查找已有的消息队列,不会创建新的消息队列。
				创建消息队列的返回值就是消息队列的msqid。如果返回值小于0就表示创建失败。
				
				注意:如果要取得已创建的消息队列,就要把第二参数,设为0,key值传入要找的那个队列的key。
				
				删除消息队列
				
				int msgctl(int msqid,int cmd,struct msqid_ds* buf)删除消息队列。
				msqid是要删除的消息队列的msqid
				cmd,在删除消息队列时使用IPC_RMID这个值(其含义是立即删除消息队列),其他的选项还有IPC_STAT是取此队列的msqid_ds的结构,IPC_SET这个是用传入的参数buf,来修改msqid_ds结构。
				msqid_ds这个结构规定了当前状态。
				
				buf这个参数只有在使用cmd为IPC_SET时才使用,其余cmd在使用这个参数时用NULL即可。
				
				注意:删除消息队列的常用方式 msgctl(mspid,IPC_RMID,NULL),消息队列在使用完之后需要删除。
				
				发送/接收消息
				
				在消息队列中存放是引种规定了格式结构的消息。
				标准的msg结构,这种结构就是放在消息队列中发送或者是接收的“消息”。这个结构中第一个成员是一个long型的变量,除此之外,可以在这个结构中的定义其他的任意数量,任意类型的成员。
				
				struct msg{
					long msgtype;//这个变量表示的是消息的类型,用以区分消息的内容,这样就可以使一个消息队列中可以存放多种消息。
					char mtext[MAX_MSG_LENGTH];//消息的正文部分。这里用的是字符串类型,也可以使用其他的类型作为消息的正文。
				}
				
				int msgsnd(int msqid,const void* ptr,size_t nbytes,int flag)发送消息
				int msgrcv(int msqid,void* ptr,size_t nbytes, long type,int flag)接受消息
				msgid,都是消息队列的标识,就是要想哪个消息队列写消息,要从哪个消息队列读取消息。
				const void* ptr,是要发送的消息的地址。(消息就是消息结构的变量)
				void* ptr,是接收消息的空间。
				nbytes,是要发送的消息的大小(长度)。
				type,是要接受的消息的类型(如果接收类型设置为0,就表示接收所有消息)
				flag,是一个标记位,一般用0作为它的值。
				
				注意:如果要接收一个没有的消息结构的类型,msgrcv函数会阻塞直到有这种消息结构类型的消息被发出。这种阻塞也可以被信号打断。
				
				
				make命令
				
				make命令使用与多文件编译或者多名令执行的脚本文件执行命令。make可以控制编译过程,只编译需要编译的文件。
				
				makefile 命令用于创建脚本文件。
				
				脚本文件格式
				
				目标文件名:条件1 条件2
				(按table键)命令.....
				目标文件名(条件1):条件a
				(按table键)命令.....
				当要得到的文件还需要起他条件时就以此类推。
				创建条件文件的命令写在目标文件的下一行且要在开头按table键。
				脚本文件中可以定义宏,格式是例:cc=g++ ,是用宏是用${cc}
				还可用占位符替代条件和相同的目标名,“${@}”在同一个目标中,可以以此替代目标名,“${?}”这个可以替换条件名。 用#开就是注释。
				
				事例:
				CC=g++
				COMPIL=-c
				NAME=-o
				cat_test : cat_impl.o cat_main.o
					${CC} ${NAME} ${@} cat_impl.o cat_main.o ;
					rm *.o  
				cat_impl.o : cat_impl.cc
					${CC} ${NAME} ${@} ${COMPIL} cat_impl.cc
				cat_main.o : cat_main.cc
					${CC} ${NAME} ${@} ${COMPIL} cat_main.cc 
				
				动态连接库
				
				写一个头文件,头文件中定义了函数,然后写.cc文件实现函数,动态连接库一定要是libxxxx.so(LIUX/UNIX)这种格式。
				现将.cc文件编译成.o文件
				g++ -c -o xxx.o xxx.cc
				g++ libxxx.so -shared xxx.o(目标文件)
				
				动态连接库的使用
				在主函数中调用了动态连接库中的函数
				需要指定动态连接库的位置,要对环境变量进行修改(LD_LIBRARY_PATH)添加上自己定义的动态连接库的路径。
				连接库是使用的名字(xxx)是去掉lib和.so就可以了
				g++ sample.cc -lxxx -Lxxx			

相关资源