------------------------------------------------------------------------
复习:昨天的东西:
----------------------------------------------------------------
ctime---------char*
^/^ localtime-> / strftime
(1) 时间: time----time_t---------------struct time
<-mktime
/ 进程及父进程;
| system
(2) 进程: ---fork() /--execvp(filename,agrv[],NULL) //argv[]要执行的文件
| exec函数 | --execlp(filename, ... , ..., ...) 和execvp一样,不过把参数打乱了
/ / ........
/ wait(): 父进程等待子进程结束.然后回收资源.
/ waitpid():
-----------------------------------------------------------------------------------
第三天: 进程间通信:
-----------------------------------------------------------------------------------
(一) 概述:
信号系统 FIFO 文件系统. 信息队列.共享内存,
Daemon (精灵) 进程
makefiel ; 批量编译;
多态链接库: (shared object)
(1) 信号:是一种软中断;
进程通过信号来协调进程: *子进程结束:SIGCHLD
信号的产生: 自动(内核),用户,程序
信号是异步事件: 不用等这这个信号:
对信号的处理: 1. 强制忽略: [SIFKILL(内核保留信号),SIGSTP(手工 Ctrl+Z) 不能忽略 SIGSTOP(Ctrl+C) 不能忽略]
2. 扑获
SIGCHLD :默认状态;忽略: 就是父进程会忽略掉此信号;
SIGUSR1, SIGUSR2, :用户
kill 245: 向进程发一个信号: [SIGTERM]:
SIGALRM: 闹钟信号,定时信号.信号名子是整数.
-------------------------------------------------------------------------------------------
Signal 函数 用来登记下列函数:
void func(int signo) signo 是用来接收处理的信号.
格式: signal(信号,处理函数(函数指针));返回缺省的信号处理函数.
返回缺省的信号处理函数.
例子:
--------------------------------------------------
#include <iostream>
using namespace std;
#include <signal.h>
#include <unistd.h>
void func( int signo )
{
cout << "you pressed ctrl-c!" << endl;
}
int main()
{
signal(SIGINT, func);
for(;
{
cout << "sleep..." << endl;
sleep(5);
}
return 0;
}
结果:
对Ctrl+c 只接收一次,
对信号不处理,用系统的缺省处理函数.如果处理则用信号处理函数.
-------------------------------------------------------------------
signal(xh,SIG_DEF)
signal(sh,SIG_IGN)
signal(xh,SIG_ERR)
注册后就能用一回,需要重新注册一次.
------------------------------
kill 命令
kill 函数. int kill(pid_t pid,int sig);
只能杀掉有权限的进程.
----------------------------
关于 SIGCHLD 子进程结束信号.
#include <iostream>
using namespace std;
#include <unistd.h>
#include <signal.h>
void func( int signo )
{
signal(signo, func);
cout << "a child process exited. ";
int stat;
pid_t cid = wait(&stat);
cout << "it is " << cid << endl;
cout << "exit code: " << WEXITSTATUS(stat) << endl;
}
int main()
{
signal(SIGCHLD, func);
if( fork()==0 )
{
cout << "child1:" << getpid()<<endl;
sleep(10);
return 50;
}
if( fork()==0 )
{
cout << "child2:" << getpid()<<endl;
sleep(30);
return 100;
}
for(int i=0; i<50; i++ )
{
cout << "parent does something" << endl;
sleep(1);
}
return 0;
}
父进程不会进入堵塞状态.
-------------------
信号会打断父进程的堵塞,状态 例如:sleep() ,cin>>
演示程序:
------------
#include <iostream>
using namespace std;
#include <unistd.h>
#include <signal.h>
void func( int signo )
{
signal(signo, func);
cout << "a child process exited. ";
int stat;
pid_t cid = wait(&stat);
cout << "it is " << cid << endl;
cout << "exit code: " << WEXITSTATUS(stat) << endl;
}
int main()
{
signal(SIGCHLD, func);
if( fork()==0 )
{
cout << "child1:" << getpid()<<endl;
sleep(10);
return 50;
}
if( fork()==0 )
{
cout << "child2:" << getpid()<<endl;
sleep(20);
return 100;
}
for(int i=0; i<2; i++ )
{
cout << "parent does something" << endl;
sleep(50);
}
cout << "parent exited." << endl;
return 0;
}
结果:
child1:7529
child2:7530
parent does something
a child process exited. it is 7529
exit code: 50
parent does something
a child process exited. it is 7530
exit code: 100
parent exited.
--------------------------------------------
关于cin>>的堵塞;
演示程序
#include <iostream>
using namespace std;
#include <unistd.h>
#include <signal.h>
void func( int signo )
{
signal(signo, func);
cout << "a child process exited. ";
int stat;
pid_t cid = wait(&stat);
cout << "it is " << cid << endl;
cout << "exit code: " << WEXITSTATUS(stat) << endl;
}
int main()
{
signal(SIGCHLD, func);
if( fork()==0 )
{
cout << "child1:" << getpid()<<endl;
sleep(10);
return 50;
}
if( fork()==0 )
{
cout << "child2:" << getpid()<<endl;
sleep(20);
return 100;
}
for( int i=0; i<10; i++ )
{
cout << "input a integer:";
int n;
cin >> n;
cout << "n=" << n << endl;
}
cout << "parent exited." << endl;
return 0;
}
结果:
child1:7726
input a integer:child2:7727
adfaf
n=4
input a integer:n=4
input a integer:n=4
input a integer:n=4
input a integer:n=4
input a integer:n=4
input a integer:n=4
input a integer:n=4
input a integer:n=4
input a integer:n=4
parent exited.
-----------------------------------------------------
因此,所有的堵塞都可能被打断.
----------------------------------------------
Pause() 函数: 永远堵塞,直到有信号来
例子:
--------------------
Alarm() 函数 //等待XX秒后系统自动发出信号.
演示程序:
==============================
#include <iostream>
using namespace std;
#include <unistd.h>
#include <signal.h>
void func( int signo )
{
signal(signo, func);
cout << "caught signal..." << endl;
}
int main()
{
signal(SIGALRM, func);
alarm(10);
cout << "ready for pause..." << endl;
pause();
cout << "after pause..." << endl;
return 0;
}
结果:
ready for pause...
caught signal...
after pause...
===================================
SIGCHLE| 重复登记,打断堵塞
------------------------------
SIGALRM|SIGUSR1
SIGINT|SIGUSR2
SIGTERM|
SIGSTP|
------------------------------
=========================================================================
(5) 精灵进程
精灵进程,(daemon) 服务进程. 可能是:孤儿进程.
由若干个进程组成是 session
setsid(); //彻底没有控制终端.
标准精灵进程写法:
1. 父进程的ID=1 (终止父进程)
2. pgid 与 sid 就是它自己 (setsid())
3. 屏蔽输出终端(0,1,2)
精灵进程而标准写法:
---------------------------------------------
一般不通过终端和用户进行交流,一般通过文件来操作.
精灵进程演示程序:
#include <iostream>
using namespace std;
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
int main()
{
pid_t pid;
pid=fork();
if(pid!=0)
return 0;
cout<<"children id="<<getpid()<<endl;
setsid(); //彻底没有控制终端.
umask(0); //屏蔽其他用户对此进程的权限 如果是0 表示不屏蔽任何权限.
for(int i=0;i<256;i++)
close(i); //关掉所有的文件描述符,这样精灵进程就不再持有从父进程继承来的某些文件描述符,关哪些描述符,和具体的精灵进程有关,在这里关掉了所有的文件描述符.// 注: shell 产生的3个标准文件描述符 (0,1,2) 分别对应 (cin,cout,cerr)
for(int i=0;i<100;i++){
ofstream fout("chen",ios::app); //以追加方式向文件中写数据.
fout<<i<<" ";
fout.close();
sleep(1); //每妙中向文件中写一个数字.
}
return 0;
}
执行结果:
执行过后父进程结束,SHELL 认为此进程结束,退出进程.然后通过ps -el |grep a.out 查看 此进程还在.然后关掉SHELL
再执行ps -el |grep a.out 此进程还存在说明此进程脱离了终端控制.成为了精灵进程.
看执行后的文件.
[soft@localhost chen]$ cat chen
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
========================================================================================================================
(6) 文件队列
fifo // 文件实现的队列 称之为管道, 实现进程之间通信.pipe. 必需两端都开.
也就是说,必需有人读有人写.
mkfifo //命令来创建一个队列文件.
命令 >mkfifo a.fifo // 此文件用一个终端打不开. 用VIM 打开时后VIM 处于等待状态.
打开 open 写: write 关闭: close 读: read
管道实现程序:
===========================
fifo 特性:所有没读取的数据都变成0;
效率不高:
文件队列演示程序:
1. 写一个向管道文件写入的程序;
#include <iostream>
using namespace std;
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
cout<<"open a file "<<endl;
int fd=open("a.fifo",O_WRONLY);
if(open<0){
cout<<"failed! "<<endl;
return 0;
}
//cout<<"opened!"<<endl;
char txt[100];
for(;;){
cout<<"txt";
cin.getline(txt,100);
if(txt[0]=='q'){
return 0;
}
write(fd,txt,100);
cin.clear();
}
close(fd);
return 0;
}
执行结果
当另一个终端打开时:
open a file
txt:你好
txt:
------------------------
2. 写一个度管道文件的程序:
#include <iostream>
using namespace std;
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
cout<<"open a.fifo ......"<<endl;
int fd=open("a.fifo",O_RDONLY);
if(fd<0){
cout<<"failed!"<<endl;
return 0;
}
char buf[100];
for(;;){
int a=read(fd,buf,100);
cout<<"a="<<a<<endl;
if(a==0){
cout<<"The witer is powwer off!"<<endl;
}
if(a<=0)
break;
cout<<"buf="<<buf<<endl;
}
close(fd);
return 0;
}
执行结果:
open a.fifo ......
a=100
buf=你好
The witer is powwer off!
总结: 1. 首先该导入的头文件一定要导入. 2.要想无限循环的输入和输出要用到无限循环(呵呵,很傻,谁都知道)
---------------------------------------------------------------------------------------
(7) 消息队列
步骤:
1. 创建一个消息队列: 用 msgget(KEY,IPC_CREAT|0600)
-------------------------------
首先,要建立一个头文件:
#ifndef _MSG_H_
#define _MSG_H_
struct Stu{
char name[20];
int age;
};
struct mstu{
long type;
Stu s;
};
#endif
----------------------
演示程序:
======================================================
#include <iostream>
using namespace std;
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main( int argc, char* argv[] )
{
if( argc!=2 )
{
cout << *argv << " key" << endl;
return 0;
}
key_t key = atoi(argv[1]);
int qid = msgget(key, IPC_CREAT|0600);
if( qid<0 )
cout << "fail!" << endl;
else
cout << "OK!" << qid << endl;
return 0;
}
--------------------------
执行结果:
finished! key=32769
要想杀掉此(队列)进程: 用 ipcrm -q 32769
=========================================================
2. 向自己的消息队列中写入东西
-----------------------------
演示程序:
#include <iostream>
using namespace std;
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include "msg.h"
int main(int argc,char* argv[])
{
if(argc!=2){
cout<<*argv<<"key"<<endl;
return 0;
}
key_t key=atoi(argv[1]);
int qid=msgget(key,0);
if(qid<0)
cout<<"no found this queue!"<<endl;
else
cout<<"the queie is : "<<qid<<endl;
mstu m;
cout<<"input name and age!"<<endl;
cin>>m.s.name>>m.s.age;
cout<<"input queue type!"<<endl;
cin>>m.type;
if(msgsnd(qid,&m,sizeof(m),0)<0)
cout<<"send error!"<<endl;
else
cout<<"finished!"<<endl;
return 0;
}
结果:
the queie is : 98304
input name and age!
chenpy
21
input queue type!
100
finished!
==========================================
3. 查找消息队列中存储的消息;
----------------------------
演示程序:
#include <iostream>
using namespace std;
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "msg.h"
int main(int argc,char* argv[])
{
if(argc!=2){
cout<<*argv<<"key"<<endl;
return 0;
}
key_t key=atoi(argv[1]);
int qid=msgget(key,0);
if(qid<0)
cout<<"not found!"<<endl;
else
cout<<"finished"<<endl;
mstu m;
cout<<"input the type!"<<endl;
cin>>m.type;
if(msgrcv(qid,&m,sizeof(m),m.type,0)<0)
cout<<"recive error!!"<<endl;
else{
cout<<"type="<<m.type<<endl;
cout<<"name="<<m.s.name<<endl;
cout<<"age="<<m.s.age<<endl;
}
}
结果:
finished
input the type!
100
type=100
name=chenpy
age=21
================================================================
用消息队列 message queue
由内核维护的链表: 用消息
消息结构:
struct msgbuf{
long mgype; //必需是LONG 型 表示消息的类型;
char mtext[MAX_MSG_LENGTH]; //随便实现:
int msgget(key_t key//指定一个不存在的ID,int flag //权限)
//如果是查找flag 用0 //创建成功返回消息队列ID; 通过KEY来接收不同的信息.
ipcs 进程间通信 .
int msgcti//向消息队列中发送,消息
//接收消息
//控制消息队列
返回类型都是 INT 不成功-1,成功
//读的时候要指明类型;
//ipcrm -q +信息号 例如: ipcrm
---------------------------------------------------------------------------------
//减少重复的编译 用makefile
#说明信息
#
mg:msgget.o
g++ msgget.o -o mg //前面必需是Table
msgget.o:msgget.cc
g++ -c msgget.cc //前面必需是Table
---------------------------------------------------------------------------------
#ifndef _DATE_H_
#define _DATE_H_
struct Date{
int y;
int m;
int d;
};
void input( Date& d );
void output( const Date& d );
#endif
//$^
//g++ $^ -o $@
//g++ -c $<
=====================================================================
///编译成库文件: g++ -shared -o libas.so addsub.cc
// 生成一个库文件: libas.so* as 是库名;
如果想用一下: