Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1136477
  • 博文数量: 646
  • 博客积分: 288
  • 博客等级: 二等列兵
  • 技术积分: 5375
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-08 14:33
个人简介

为了技术,我不会停下学习的脚步,我相信我还能走二十年。

文章分类

全部博文(646)

文章存档

2014年(8)

2013年(134)

2012年(504)

分类: LINUX

2013-02-26 10:38:46

一、管道

1、管道(有亲缘关系)及有名管道(无亲缘)、信号、消息队列、共享内存、信号量、套接字。

=====无名管道

2、管道:是堵塞的;管道的读端存在时向管道中写入数据才有意义。具有固定的读端和写端。

3、当一个管道建立pipe(fds)时,它会创建两个文件描述符 fds[0]和 fds[1]。结束后要关闭,close(fds[0]);close(fds[1]);

4、一般是先建一个管道,再通过fork(),则会有两个管道。其中 fds[0]固定用于读管道,而 fd[1]固定用于写管道具有父子亲缘关系。为了实现父子进程之间的读写,只需把无关的读端或写端的文件描述符关闭即可。一边读,一边写。


5、最后也要等待,等子进程结束后父进程再结束。防止僵尸进程,没人收。

6、注意:1.只有在管道的读端存在时向管道中写入数据才有意义。2.向管道中写入数据时,linux 将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读取管道缓冲区中的数据,那么写操作将会一直阻塞。3.父子进程在运行时,它们的先后次序并不能保证,因此,在这里为了保证父进程已经关闭了读描述符,可在子进程中调用 sleep 函数。

=======标准流管道

1、标准流管道:用来创建一个连接到另一个进程的管道。所以不属于有名或无名管道。

2、popen"r"只是把结果作为输出,但还没有输出。返回的是管道的文件描述符。"w"貌似不可用-lai==对应 pclose(fd)

=======有名管道(相当于把创建的文件当做管道连接,然后像对普通文件一样进行读写。文件也就是管道可以通过路径名来指出,而且在文件系统中是可见的)

1、有名管道:互不相关的两个进程实现彼此通信。(mkfifo)管道可以通过路径名来指出,也可以mknod  管道名  p  来创建

2、普通文件读写不会出现堵塞问题,管道读写中却有堵塞的可能。非堵塞标志:O_NONBLOCK.

3、如果文件已经存在,则也可以成功,但是会出现“交叉读写”现象,所以尽量避免。

4、但是以上测试还是有点问题,最好用完后就删掉,不然第二次编译不了===

5、#define FIFO_SERVER "/linux_basic_study/pro_communication/myfifo"

6、//只要创建一次,文件就会存在,以后直接打开也可以。

//可以看到以P开头的管道文件在/linux_basic_study/myfifo

//errno是系统定义的全局变量,函数发生异常时,一般会将errno变量(include  errno.h)赋一个整数值,

//不同的值表示不同的含义,可以通过查看该值推测出错的原因.

7.//阻塞读时要每读一次就open一次阻塞仅在第一次读有效。否则第一次堵塞后,后面就不堵塞了。//非阻塞时open要放while外面,不然接收不到数据.

8.unlink(FIFO);//删除文件。记住:要保证里面没有文件。对应第四条。

======================================================================

二、信号通信

1.信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。信号可以直接进行用户空间进程和内核进程之间的交互。相当于我们的中断处理函数

2.信号生命周期3个重要阶段==>通过四个画面:信号产生(内核)、信号在进程中注册(用户进程)、信号在进程中注销(用户进程)、执行信号处理函数。

3.不可靠信号(前)32个,若发现同样的该信号已经注册,则忽略。可靠信号则会再次注册。

4.注意:信号的产生、注册、注销等是指信号的内部实现机制,而不是信号的函数实现。

5.三种=>忽略信号(SIGKILLSIGSTOP不能被忽略):对信号不做处理;捕捉信号:当信号发生时,执行相应的处理函数;执行缺省操作:Linux 对每种信号都规定了默认操作。

6.重要的六个信号:SIGINT=>(CTRL+C)f发出;  SIGQUIT=>(CTRL+\) SIGKILL SIGALARM SIGSTOP SIGCHLD=>(CTRL+Z)

7.Alarm()一个进程只能有一个闹钟时间。时间到后,发出SIGALRM信号,自动终止 程序执行 。

8.Pause()用于将调用进程挂起直至捕捉到信号为止。

9.Raise()类似于kill函数允许进程而且只能向自身发送信号。

10.Kill()不仅可以中止进程(实际上发出 SIGKILL 信号),也可以向进程发送其他 信号。

11.信号处理的主要方法有两种,一种是使用简单的 signal 函数 eg:signal(SIGINT, my_func);,另一种是 使用信号集函数组。

12.父进程为1是孤儿进程,是脱离控制台。Kill不掉。SIGSTOP用产生。。 只能重启系统才能关掉孤儿进程。所以最好发送KILL信号,不要发送stop

三、共享内存(创建一个共享内存,可以映射到自己的内存上,通过同步机制。)

利用共享内存存在问题:如果在循环里面,它会循环读取已经读过的内容。

可同时利用后面讲到的消息队列解决这个问题。

1、共享内存是一种最为高效的进程间通信方式。===>非阻塞。。。删除一次就可以了,删除两次会出错。

2、是将需要访问的内存映射到自己私有的地址空间。所以相当于访问自己的内存。


3、步骤:1,创建共享内存:最好ipc_creat(没有e...不然如果这个key 的内存没有 创建的话会找不到文件会报错。返回的是共享内存 区标识符

shmid = shmget((key_t)100,BUFSZ,0666|IPC_CREAT);

   2、映射到共享内存。返回的是共享内存映射到指定位置的指针

shmadd = shmat(shmid ,0 ,0);

3、读取或者写入

if(!strncmp(shm_ptr,"end",3)

if(!strcmp(shm_ptr, "end"))//不行,不要用,第一次可以,后面就 不行

4、撤销映射内存shmdt(shmadd)

5、删除共享内存:记住:读或者写一方删除就可以了,不然会 报错。

6、在输入时,用fgets(temp, 1024, stdin); 键盘输入,标准stdin;

scanf("%s",temp);//中间不能有空格,因为是以空格或者回车 为结束。所以不采用。

四、消息队列

1、消息队列具有一定的FIFO 的特性,但是它可以实现消息的随机 查询,比FIFO 具有更大的优势。

2、也是一个放送,一个接收。两种方法:一个用结构体,一个不要(其实项目中要的)

3、步骤:

1、创建或打开消息队列:返回的是消息队列ID

msg_id = msgget((key_t)1234, 0666 | IPC_CREAT);

2、读取消息:

msgrcv(msg_id,buf, BUFSIZ, 0, 0)

2、发送添加消息:

msgsnd(message_id,buf,BUFSZ,0)

3、控制消息队列:相当于撤销,删除。

msgctl(message_id, IPC_RMID, 0) 

4、利用结构体,发送数据,但发送过去的只是字符串,而 message_type只是作为接收第几个信息的标志。所以一 般用另一 种。

阅读(612) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~