c++笔记3

来源:互联网 发布:爱奇艺网络异常101 编辑:程序博客网 时间:2024/05/21 05:20

------------------------------------------------------------------------
复习:昨天的东西:
----------------------------------------------------------------
             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 是库名
;
如果想用一下:

 

 
原创粉丝点击