本文主要是介绍Linux进程与线程之四,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
每日一结
一 传统的进程间通信
1.信号 : 异步进程间通信方式
信号是对中断机制的一种模拟
进程对信号处理方式:
(1)忽略信号
SIGKILL ,SIGSTOP 不能忽略
(2)捕捉 : 信号到达的时候,执行信号处理函数
(3)缺省操作 : 系统默认的操作
大部分信号默认的操作都是杀死进程,SIGCHLD 进程默认忽略。
SIGCHLD在子进程状态发生改变的时候,发送父进程 。
2.设置进程对信号的处理方式
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
参数:
@signum 信号序号
@handler SIG_IGN:忽略 SIG_DFL:默认的处理方式 函数名:捕捉
返回值:
成功返回处理函数的入口地址,失败返回SIG_ERR
注:查看一下man page,解释一下其中的参数,以及总结一下,对于这类参数,该怎么去看。
练习:
回收僵尸态子进程,父进程不能轮询,不能阻塞 ?
(1).创建一个子进程,睡眠3s后退出
(2).父进程每隔1s输出一个字符串
wait / waitpid
3.设置闹钟
unsigned int alarm(unsigned int seconds);
功能:给进程启动一个定时器,定时器时间达到,内核会向进程发送SIGALRM
参数:
@seconds 秒
返回值:
成功返回0,失败返回 -1
练习:
探测用户有没有输入,如果3s内用户没有输入,则超时一次 ,如果超时三次进程自动结束
代码示例如下:
代码分析如下:
思考一下,其整个进程运行的流程
4.挂起进程
int pause(void);
特点:挂起一个进程,直到进程收到一个信号,进程会继续执行
代码示例如下:
分析其原因:
注意:对于这个程序的运行结果,自己好好思考一下
注意:大部分信号对进程的默认操作都是杀死进程,此时必须设置进程对信号处理方式为捕捉
信号是个什么东西?信号是怎么进行进程间通信的?
信号是在软件层次上对中断机制的一种模拟。在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的:一个进程不必通过任何操作来等待信号的到达。事实上,进程也不知道信号到底什么时候到达。信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了那些系统事件。他可以在任何时候发给某一进程,而无需知道该进程的状态。如果该进程当前并未处于执行态,则该信号就有内核保存起来,知道该进程恢复执行再传递给它为止;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,知道其阻塞被取消时才被传递给进程。信号是进程间通信机制中唯一的异步通信机制。
怎么区分同步通知和异步通知?
信号可以直接进行用户空间进程和内核进程之间的交互
同步和异步的区别:
1、同步就是说多个任务之间是有先后关系的,一个任务需要等待另一个任务执行完毕才能继续执行。
2、异步就是说多个任务之间没有先后关系,不需要相互等待各做各的事。
同步编程方法:
1、信号量
2、互斥量
异步无需考虑资源冲突,不需特别处理。
关于Linux环境进程间通信的参考资料(二): 信号
上:http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html
下:http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index2.html
二 IPC对象
1.消息队列
(1)创建消息队列
int msgget(key_t key, int msgflg);
功能:获取指定的key值的消息队列ID
参数:
@key
<1>IPC_PRIVATE:每次都会创建一个新的消息队列 [用在亲缘关系的进程间通信]
<2>ftok函数获的key [用在非亲缘关系进程间通信]
key_t ftok(const char *pathname, int proj_id);
功能:根据文件的ID 和 proj_id的低8bit产生一个key值
参数:
@pathname 一个文件名
@proj_id 一个字符
返回值:
成功返回key,失败返回-1
@msgflg :IPC_CREAT , IPC_EXCL
IPC_CREAT | 0666 -> 如果执行的key的消息队列不存在,则创建新的消息队列
IPC_CREAT | IPC_EXCL -> 判别指定key的消息队列是否存在,如果存在则报错
返回值:
成功返回消息队列ID,失败返回-1
--------------------------------------------------
通过命令查看IPC对象:
ipcs -m/-s/-q
m:共享内存对象
s:信号灯集对象
q:消息队列对象
ipcrm -m/-s/-q ID
删除IPC对象
--------------------------------------------------
(2)添加消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
@msqid 消息队列的ID
@msgp 消息存放的地址
@msgsz 消息正文的大小
@msgflg 0:阻塞的方式调用 IPC_NOWAIT:非阻塞的方式调用
返回值:成功返回0,失败返回-1
-----------------------------------------------------------
消息结构体:
typedef struct
{
//第一个字段必须是消息类型
long type;
//消息正文部分
char buf[1024];
int pid;
..
}MSG;
//计算消息正文的大小
#define MTXT_SIZE (sizeof(MSG) - sizeof(long))
-----------------------------------------------------------
MSG msg;
msg.type = 100;
fgets(msg.buf,sizeof(msg.buf),stdin);
msg.pid = getpid();
msgsnd(msgid,&msg,MTXT_SIZE,0);
(3)接受消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:
@msqid 消息队列的ID
@msgp 消息存放的地址
@msgsz 消息正文的大小
@msgtyp 消息的类型
@msgflg 0:阻塞的方式调用 IPC_NOWAIT:非阻塞的方式调用
返回值:成功返回接受的消息正文大小,失败返回-1
练习:
A,B进程通过消息队列通信[A,B进程没有亲缘关系]
示例如下:
进程A:
进程B:
代码分析如下:
关于Linux环境进程间通信的参考资料:
消息队列
http://www.ibm.com/developerworks/cn/linux/l-ipc/part3/
Linux下进程间通信方式的概述:
I.传统的进程间通信方式
有名管道(pipe),有名管道(fifo)和信号(signal)
II.system V IPC对象
共享内存(share memory),消息队列(message queue)和信号灯(semaphore)
III.BSD
套接字(socket)
关注微信公众号获取更多资讯
这篇关于Linux进程与线程之四的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!