一、程序存储
经常被问到进程与线程的区别,今天有人问程序与进程的区别,一下子还真没反应过来
。程序只是一组指令的有序集合,它本身没有任何运行的含义,它只是一个静态的实体。而进程则不同,它是程序在某个数据集上的执行。进程是一个动态的实体,它有自己的生命周期。反映了一个程序在一定的数据集上运行的全部动态过程。
二、crontab
基本格式 :
* * * * * command
分 时 日 月 周 命令第1列表示分钟1~59 每分钟用*或者 */1表示
第2列表示小时1~23(0表示0点)
第3列表示日期1~31
第4列表示月份1~12
第5列标识号星期0~6(0表示星期天)
第6列要运行的命令
在终端输入:crontab -e
然后编辑内容为:* * 9 10 0 echo "now the time is .... `date` " >>/home/fsy/io/tempfile
查看:crontab -l
删除:crontab -r
三、关于fork 进程的补充
1、用重定向方式输出时应该注意:调用fork的程序,会完全复制一个父进程。所以也会复制一个缓冲区,及如果父进程在缓冲区中有内容,则子进程也会一并获得。那为什么对文件的读写不是两个文件呢?因为子进程复制的是文件标示符,转成文件指针会指向同一个文件。
2、fork用于父子进程同时指行不同的代码段,比如网络服务进程。或用于要执行一个不同的程序,通常是子进程从fork返回后立即调用exec。
3、vfrok()不复制父进程的地址空间。子进程一定是先运行。在调用exec/exit之前,它在父进程的空间中运行。
四、exec族
函数还真多,就是功能都一样。一大家子人,长的还差不多,只能干一样事。这存在感,真服了
个人感觉记住一个就行:execlp("ls","ls","-l",NULL);
错误判断:
errno=ENOENT 找不到文件或路径
errno=EFAULT argv/envp忘记用NULL结束
errno=EACCES 没有运行权限
五、exit()与_exit()
最好使用exit()退出程序。因为会清空缓存。exit()在<stdlib.h>中。_exit()在<unistd.h>中。中间的参数,可以用wait系统调用接收子进程返回值。
六、wait与waitpid()
wait()使父进程阻塞直到子进程结束才返回。wait()是waitpid()的一个特例。所以waitpid()更牛一些~
通常说来waitpid(),用于等待一个特定的子进程。调用方法为:waitpid(pid1, &stu, WNOHANG) 或者 waitpid(pid1, NULL, 0)
七、孤儿与僵尸(进程)
这个...不知道是作者有才,还是翻译有思想,弄出了这么俩词
![]()
父进程先死了,子进程就是孤儿了。但是别担心,咱是和 *谐社会,怎么能有孤儿呢?所以马上有个大爹——init 收养这些没人要的进程。
要是子进程先死了,父进程没回收子进程,那他就成了孤魂野鬼。也就变僵尸了
所以父进程要收尸啊...... 这个也好解决。收尸其实也不费劲,调用wait()/waitpid()就行。这个到处都是僵尸,对社会的安定团结还是有很大影响的。系统所能使用的进程号是有限的,子进程不回收,虽然不占内存了,但是进程号还占着,僵尸多了,正常的子进程就没有进程号了......
一、进程组与会话
进程组:是一个或多个进程的集合。可以调用 getpgid(0) 或 getpgrp() 来得到。进程组ID为组长的进程ID。只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关。调用 setpgid() 加入一个现有的进程组或创建一个新的进程组。
会话:一个或多个进程组的集合
可以用 setsid() 建立新会话,则该进程会变成新会话的首进程,同时成为一个新进程组的组长进程,该进程没有控制终端。
二、守护进程
守护进程的特点:没有终端的限制,不受用户、终端或其它的变化而受到影响。
创建守护进程的步骤:
出错处理:因为守护进程不依赖于终端,所以出错信息是不能用 printf 滴,这..... 怎么办?莫怕,用 syslog() 就能搞定~
用系统日志就要调用三个函数:openlog()、syslog()、closelog() 系统日志存于 /var/log/messages
举例:
- #include<stdio.h>
- #include<stdlib.h>
- #include<sys/types.h>
- #include<syslog.h>
- int main(){
- pid_t pid,s;
- int i;
- char *buff="Daemon Test!\n";
- if((pid = fork())<0){
- printf("fork error!\n");
- exit(1);
- }else if(pid> 0){
- exit(0);
- }
- //第一个参数为在消息之前加入的字符串,第二个参数在每个消息中包含进程的ID,第三个参数指定程序发送的消息类型
- openlog("daemon_testlog",LOG_PID,LOG_DAEMON);
- if((s=setsid())<0){
- //第一个参数为参数类型,第二个参数为信息字符串
- syslog(LOG_ERR,"%s\n","setsid error!");
- }
- chdir("/");
- umask(0);
- for(i=0;i<getdtablesize();i++){ //关闭文件描述
- close(i);
- }
- while(1){
- syslog(LOG_INFO,"%s\n",buff);
- sleep(10);
- }
- closelog();
- return 0;
- }
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<syslog.h> int main(){ pid_t pid,s; int i; char *buff="Daemon Test!\n"; if((pid = fork())<0){ printf("fork error!\n"); exit(1); }else if(pid> 0){ exit(0); } //第一个参数为在消息之前加入的字符串,第二个参数在每个消息中包含进程的ID,第三个参数指定程序发送的消息类型 openlog("daemon_testlog",LOG_PID,LOG_DAEMON); if((s=setsid())<0){ //第一个参数为参数类型,第二个参数为信息字符串 syslog(LOG_ERR,"%s\n","setsid error!"); } chdir("/"); umask(0); for(i=0;i<getdtablesize();i++){ //关闭文件描述 close(i); } while(1){ syslog(LOG_INFO,"%s\n",buff); sleep(10); } closelog(); return 0; }
三、信号
Linux对每种信号都制定了默认的操作。捕捉到信号可以采用默认的操作、可以忽略(SIGKILL 与 SIGSTOP除外)、也可以执行相应的自定义处理函数。
kill()、raise() 发信号。一些相关知识可以参考Linux 信号通信
pause() 将进程挂起直到捕捉到信号为止。
举例1:
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- void my_func(int);
- int main() {
- printf("Wainting for signal: SIGINT/SIGQUIT...\n");
- signal(SIGINT,my_func);
- signal(SIGQUIT,my_func);
- pause();
- pause();
- exit(0);
- }
- void my_func(int sign_no){
- if (sign_no==SIGINT) {
- printf("I got CTRL+C!\n");
- } else if (sign_no==SIGQUIT) {
- printf("I got CTRL+\\!\n");
- }
- }
#include <stdio.h> #include <stdlib.h> #include <signal.h> void my_func(int); int main() { printf("Wainting for signal: SIGINT/SIGQUIT...\n"); signal(SIGINT,my_func); signal(SIGQUIT,my_func); pause(); pause(); exit(0); } void my_func(int sign_no){ if (sign_no==SIGINT) { printf("I got CTRL+C!\n"); } else if (sign_no==SIGQUIT) { printf("I got CTRL+\\!\n"); } }
举例2:
- #include<stdio.h>
- #include<stdlib.h>
- #include<sys/types.h>
- #include<signal.h>
- int main(){
- pid_t pid;
- if((pid = fork())<0){
- printf("fork error!\n");
- exit(1);
- }else if(pid == 0){
- printf("Child process wait for singal....a\n");
- raise(SIGSTOP); //子进程向自己发送一个消息,线程停止
- printf("Child is dead\n"); //此句不会打出来,因为进程直接被kill了
- }else{
- sleep(10);
- kill(pid,SIGKILL);
- wait(NULL);
- }
- return 0;
- }
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<signal.h> int main(){ pid_t pid; if((pid = fork())<0){ printf("fork error!\n"); exit(1); }else if(pid == 0){ printf("Child process wait for singal....a\n"); raise(SIGSTOP); //子进程向自己发送一个消息,线程停止 printf("Child is dead\n"); //此句不会打出来,因为进程直接被kill了 }else{ sleep(10); kill(pid,SIGKILL); wait(NULL); } return 0; }
alarm() 在进程中设置一个定时器,当时间到时,发出SIGALARM信号。一个进程只能有一个闹钟时间,新的将代替旧的。返回值为新旧时间差值。
举例:
- #include<stdio.h>
- #include<stdlib.h>
- #include<sys/types.h>
- #include<signal.h>
- int main(){
- int ret=alarm(5);
- printf("alarm...%d\n",ret);
- sleep(3);
- ret=alarm(5);
- printf("alarm...%d\n",ret);
- pause();
- printf("never show\n");
- }
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<signal.h> int main(){ int ret=alarm(5); printf("alarm...%d\n",ret); sleep(3); ret=alarm(5); printf("alarm...%d\n",ret); pause(); printf("never show\n"); }
程序运行结果为:alarm...0 alarm....2 。 2为相差时间,程序收到SIGALARM默认执行的操作为终止线程。
sigaction()函数:signal()的高级版~
例子:
- #include<stdio.h>
- #include<stdlib.h>
- #include<sys/types.h>
- #include<signal.h>
- void my_func(int);
- int main(){
- struct sigaction sa,oldsa;
- printf("waiting for SIGINT/SIGQUIT......\n");
- sa.sa_handler=my_func; //设定处理函数
- sigemptyset(&sa.sa_mask); //清空信号集合
- sa.sa_flags=0; //对信号处理的选项一般设为0
- sigaction(SIGINT,&sa,&oldsa); //oldsa为保存旧的信号结构体
- sigaction(SIGQUIT,&sa,&oldsa);
- pause();
- pause();
- pause();
- pause();
- pause();
- pause();
- pause();
- }
- void my_func(int sig){
- if(sig == SIGINT){
- printf("Receive CTRL+C!\n");
- }
- else if(sig == SIGQUIT){
- printf("Receive CTRL+\\!\n");
- }else
- printf("Receive Signal!\n");
- }
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<signal.h> void my_func(int); int main(){ struct sigaction sa,oldsa; printf("waiting for SIGINT/SIGQUIT......\n"); sa.sa_handler=my_func; //设定处理函数 sigemptyset(&sa.sa_mask); //清空信号集合 sa.sa_flags=0; //对信号处理的选项一般设为0 sigaction(SIGINT,&sa,&oldsa); //oldsa为保存旧的信号结构体 sigaction(SIGQUIT,&sa,&oldsa); pause(); pause(); pause(); pause(); pause(); pause(); pause(); } void my_func(int sig){ if(sig == SIGINT){ printf("Receive CTRL+C!\n"); } else if(sig == SIGQUIT){ printf("Receive CTRL+\\!\n"); }else printf("Receive Signal!\n"); }
信号集
通常就是这个步骤。清空信号集->添加信号->设置信号屏蔽->定义信号处理
举例:
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <unistd.h>
- void my_func(int);
- int main() {
- struct sigaction sa1,sa2;
- sigset_t set;
- //清空
- if (sigemptyset(&set)<0) {
- perror("sigemptyset");
- exit(1);
- }
- //添加信号
- if (sigaddset(&set,SIGINT)<0) {
- perror("sigaddset SIGINT");
- exit(1);
- }
- if (sigaddset(&set,SIGQUIT)<0) {
- perror("sigaddset SIGQUIT");
- exit(1);
- }
- //设置信号
- if (sigismember(&set,SIGINT)) {
- sa1.sa_handler=my_func;
- sigemptyset(&sa1.sa_mask);
- sa1.sa_flags=0;
- sigaction(SIGINT,&sa1,NULL);
- }
- if (sigismember(&set,SIGQUIT)) {
- sa2.sa_handler=SIG_DFL;
- sigemptyset(&sa2.sa_mask);
- sa2.sa_flags=0;
- sigaction(SIGQUIT,&sa2,NULL);
- }
- //设置屏蔽字
- if (sigprocmask(SIG_BLOCK,&set,NULL)<0) {
- perror("sigprocmask");
- exit(1);
- } else {
- printf("Signal set is blocked!\n");
- }
- while(1){
- int c=getchar();
- if ((c=='u')||(c=='U'))
- break;
- }
- //解除屏蔽字
- if (sigprocmask(SIG_UNBLOCK,&set,NULL)<0) {
- perror("sigprocmask");
- exit(1);
- } else {
- printf("Signal set is unblocked!\n");
- }
- }
- void my_func(int sig){
- if(sig == SIGINT){
- printf("Receive CTRL+C!\n");
- }
- else if(sig == SIGQUIT){
- printf("Receive CTRL+\\!\n");
- }else
- printf("Receive signal!\n");
- }
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <sys/types.h> #include <unistd.h> void my_func(int); int main() { struct sigaction sa1,sa2; sigset_t set; //清空 if (sigemptyset(&set)<0) { perror("sigemptyset"); exit(1); } //添加信号 if (sigaddset(&set,SIGINT)<0) { perror("sigaddset SIGINT"); exit(1); } if (sigaddset(&set,SIGQUIT)<0) { perror("sigaddset SIGQUIT"); exit(1); } //设置信号 if (sigismember(&set,SIGINT)) { sa1.sa_handler=my_func; sigemptyset(&sa1.sa_mask); sa1.sa_flags=0; sigaction(SIGINT,&sa1,NULL); } if (sigismember(&set,SIGQUIT)) { sa2.sa_handler=SIG_DFL; sigemptyset(&sa2.sa_mask); sa2.sa_flags=0; sigaction(SIGQUIT,&sa2,NULL); } //设置屏蔽字 if (sigprocmask(SIG_BLOCK,&set,NULL)<0) { perror("sigprocmask"); exit(1); } else { printf("Signal set is blocked!\n"); } while(1){ int c=getchar(); if ((c=='u')||(c=='U')) break; } //解除屏蔽字 if (sigprocmask(SIG_UNBLOCK,&set,NULL)<0) { perror("sigprocmask"); exit(1); } else { printf("Signal set is unblocked!\n"); } } void my_func(int sig){ if(sig == SIGINT){ printf("Receive CTRL+C!\n"); } else if(sig == SIGQUIT){ printf("Receive CTRL+\\!\n"); }else printf("Receive signal!\n"); }
[注] 1、解锁的瞬间即调用处理函数。2、内核只会保存一个同类的信号,其他的都被丢掉了。
一、文件锁
文件锁用于多个用户共同使用或操作同一个文件。有读锁的时候可以再加读锁,不能再加写锁。有写锁的时候,不能加任何锁,加读锁时,该描述符必须是读打开,加写锁时,该描述符必须是写打开,且只在进程间有用。
重写的上锁方法
- //lock.c
- int lock_set(int fd,int type){
- struct flock lock;
- lock.l_type=type;
- lock.l_start=0;
- lock.l_whence=SEEK_SET;
- lock.l_len = 0;
- lock.l_pid=-1;
- fcntl(fd,F_GETLK,&lock);
- if(lock.l_type!=F_UNLCK){
- if(lock.l_type == F_RDLCK)
- printf("Read lock already set by %d!\n",lock.l_pid);
- else if(lock.l_type == F_WRLCK)
- printf("Write lock already set by %d!\n",lock.l_pid);
- }
- lock.l_type = type;
- //此处的F_SETLKW为F_SETLK的阻塞版本,当无法获取锁时进入睡眠等待状态
- if(fcntl(fd,F_SETLKW,&lock)<0){
- printf("Lock failed:type=%d!\n",lock.l_type);
- exit(1);
- }
- switch(lock.l_type){
- case F_RDLCK:
- printf("read lock set by %d\n",getpid());
- break;
- case F_WRLCK:
- printf("write lock set by %d\n",getpid());
- break;
- case F_UNLCK:
- printf("UN lock set by %d\n",getpid());
- break;
- default:
- break;
- }
- }
//lock.c int lock_set(int fd,int type){ struct flock lock; lock.l_type=type; lock.l_start=0; lock.l_whence=SEEK_SET; lock.l_len = 0; lock.l_pid=-1; fcntl(fd,F_GETLK,&lock); if(lock.l_type!=F_UNLCK){ if(lock.l_type == F_RDLCK) printf("Read lock already set by %d!\n",lock.l_pid); else if(lock.l_type == F_WRLCK) printf("Write lock already set by %d!\n",lock.l_pid); } lock.l_type = type; //此处的F_SETLKW为F_SETLK的阻塞版本,当无法获取锁时进入睡眠等待状态 if(fcntl(fd,F_SETLKW,&lock)<0){ printf("Lock failed:type=%d!\n",lock.l_type); exit(1); } switch(lock.l_type){ case F_RDLCK: printf("read lock set by %d\n",getpid()); break; case F_WRLCK: printf("write lock set by %d\n",getpid()); break; case F_UNLCK: printf("UN lock set by %d\n",getpid()); break; default: break; } }
上写锁
- #include<stdio.h>
- #include<fcntl.h>
- #include<unistd.h>
- #include"lock.c"
- int main(){
- int fd;
- fd=open("readme",O_RDWR|O_CREAT,0666);
- if(fd<0){
- printf("Open file error\n");
- exit(1);
- }
- lock_set(fd,F_WRLCK);
- getchar();
- lock_set(fd,F_UNLCK);
- getchar();
- return 0;
- }
#include<stdio.h> #include<fcntl.h> #include<unistd.h> #include"lock.c" int main(){ int fd; fd=open("readme",O_RDWR|O_CREAT,0666); if(fd<0){ printf("Open file error\n"); exit(1); } lock_set(fd,F_WRLCK); getchar(); lock_set(fd,F_UNLCK); getchar(); return 0; }
上读锁
- #include<stdio.h>
- #include<fcntl.h>
- #include<unistd.h>
- #include"lock.c"
- int main(){
- int fd;
- fd=open("readme",O_RDWR|O_CREAT,0666);
- if(fd<0){
- printf("Open file error\n");
- exit(1);
- }
- lock_set(fd,F_RDLCK);
- getchar();
- lock_set(fd,F_UNLCK);
- getchar();
- return 0;
- }
#include<stdio.h> #include<fcntl.h> #include<unistd.h> #include"lock.c" int main(){ int fd; fd=open("readme",O_RDWR|O_CREAT,0666); if(fd<0){ printf("Open file error\n"); exit(1); } lock_set(fd,F_RDLCK); getchar(); lock_set(fd,F_UNLCK); getchar(); return 0; }
在两个终端中测试:
两个终端可以同时加上读锁。
有一个终端加上读锁,则必须等读锁释放才能加写锁。
有一个终端加写锁必须释放才能加别的锁。
二、多路复用:select、poll
- #include<stdio.h>
- #include<fcntl.h>
- #include<unistd.h>
- #include<memory.h>
- #define MAX(a,b) (a>b?a:b)
- int main(){
- int fd[3];
- char buff[1024];
- int res,max_fd,i,num;
- fd_set insert,temp_insert;
- struct timeval tv;
- fd[0]=0;
- if((fd[1]=open("in1",O_RDONLY|O_NONBLOCK))<0){
- printf("open in1 error!\n");
- return 1;
- }
- if((fd[2]=open("in2",O_RDONLY|O_NONBLOCK))<0){
- printf("open in2 error!\n");
- return 1;
- }
- //选出最大的fd,select()函数用的
- max_fd=MAX(MAX(fd[0],fd[1]),fd[2]);
- //清空fd_set
- FD_ZERO(&insert);
- for(i=0;i<3;i++){
- FD_SET(fd[i],&insert);
- }
- //设置延迟
- tv.tv_sec=60;
- tv.tv_usec=0;
- while(FD_ISSET(fd[0],&insert) || FD_ISSET(fd[1],&insert) || FD_ISSET(fd[2],&insert)){
- temp_insert = insert;
- //select函数会对fd_set产生修改,只保存变化的文件符,所以要用一个temp
- res=select(max_fd+1,&temp_insert,NULL,NULL,&tv);
- switch(res){
- case -1:
- printf("select error!\n");
- return 1;
- break;
- case 0:
- printf("time out\n");
- return 1;
- break;
- default:
- for(i=0;i<3;i++){
- if(FD_ISSET(fd[i],&temp_insert)){
- memset(buff,0,1024);
- num=read(fd[i],buff,1024);
- if(num<0){
- return 1;
- }else if(num == 0){
- close(fd[i]);
- FD_CLR(fd[i],&insert);
- }else{
- if(i == 0){
- if((buff[0] == 'q') || (buff[0] == 'Q')){
- return 0;
- }
- }
- write(STDOUT_FILENO,buff,num);
- }
- }
- }
- }
- }
- }
#include<stdio.h> #include<fcntl.h> #include<unistd.h> #include<memory.h> #define MAX(a,b) (a>b?a:b) int main(){ int fd[3]; char buff[1024]; int res,max_fd,i,num; fd_set insert,temp_insert; struct timeval tv; fd[0]=0; if((fd[1]=open("in1",O_RDONLY|O_NONBLOCK))<0){ printf("open in1 error!\n"); return 1; } if((fd[2]=open("in2",O_RDONLY|O_NONBLOCK))<0){ printf("open in2 error!\n"); return 1; } //选出最大的fd,select()函数用的 max_fd=MAX(MAX(fd[0],fd[1]),fd[2]); //清空fd_set FD_ZERO(&insert); for(i=0;i<3;i++){ FD_SET(fd[i],&insert); } //设置延迟 tv.tv_sec=60; tv.tv_usec=0; while(FD_ISSET(fd[0],&insert) || FD_ISSET(fd[1],&insert) || FD_ISSET(fd[2],&insert)){ temp_insert = insert; //select函数会对fd_set产生修改,只保存变化的文件符,所以要用一个temp res=select(max_fd+1,&temp_insert,NULL,NULL,&tv); switch(res){ case -1: printf("select error!\n"); return 1; break; case 0: printf("time out\n"); return 1; break; default: for(i=0;i<3;i++){ if(FD_ISSET(fd[i],&temp_insert)){ memset(buff,0,1024); num=read(fd[i],buff,1024); if(num<0){ return 1; }else if(num == 0){ close(fd[i]); FD_CLR(fd[i],&insert); }else{ if(i == 0){ if((buff[0] == 'q') || (buff[0] == 'Q')){ return 0; } } write(STDOUT_FILENO,buff,num); } } } } } }
poll用法与select很相似,只是在一些变量上有些不同:
- #include <unistd.h>
- #include <fcntl.h>
- #include <time.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <poll.h>
- #define MAX_BUFFER_SIZE 1024
- #define IO_IN_FILES 3
- #define TIME_DELAY 60000
- int main() {
- struct pollfd fds[IO_IN_FILES];
- char buff[MAX_BUFFER_SIZE];
- int i,res,real_read;
- fds[0].fd=0;
- if((fds[1].fd=open("in1",O_RDONLY|O_NONBLOCK))<0) {
- printf("Open in1 error!\n");
- return 1;
- }
- if((fds[2].fd=open("in2",O_RDONLY|O_NONBLOCK))<0) {
- printf("Open in2 error!\n");
- return 1;
- }
- for(i=0;i<IO_IN_FILES;i++)
- fds[i].events=POLLIN;
- while(fds[0].events||fds[1].events||fds[2].events) {
- res=poll(fds,IO_IN_FILES,TIME_DELAY);
- switch(res) {
- case -1:
- printf("POLL error!\n");
- return 1;
- break;
- case 0:
- printf("Time out!\n");
- return 1;
- break;
- default:
- for(i=0;i<IO_IN_FILES;i++) {
- if(fds[i].revents) {
- memset(buff,0,MAX_BUFFER_SIZE);
- real_read=read(fds[i].fd,buff,MAX_BUFFER_SIZE);
- if(real_read<0){
- printf("Read error!\n");
- return 1;
- } else if (real_read==0) {
- close(fds[i].fd);
- fds[i].events=0;
- } else {
- if (i==0) {
- if((buff[0]=='q')||(buff[0]=='Q'))
- return 0;
- } else {
- write(STDOUT_FILENO, buff,real_read);
- // buff[real_read]='\0';
- // printf("%s",buff);
- }
- }
- }
- }
- }
- }
- return 0;
- }
#include <unistd.h> #include <fcntl.h> #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <poll.h> #define MAX_BUFFER_SIZE 1024 #define IO_IN_FILES 3 #define TIME_DELAY 60000 int main() { struct pollfd fds[IO_IN_FILES]; char buff[MAX_BUFFER_SIZE]; int i,res,real_read; fds[0].fd=0; if((fds[1].fd=open("in1",O_RDONLY|O_NONBLOCK))<0) { printf("Open in1 error!\n"); return 1; } if((fds[2].fd=open("in2",O_RDONLY|O_NONBLOCK))<0) { printf("Open in2 error!\n"); return 1; } for(i=0;i<IO_IN_FILES;i++) fds[i].events=POLLIN; while(fds[0].events||fds[1].events||fds[2].events) { res=poll(fds,IO_IN_FILES,TIME_DELAY); switch(res) { case -1: printf("POLL error!\n"); return 1; break; case 0: printf("Time out!\n"); return 1; break; default: for(i=0;i<IO_IN_FILES;i++) { if(fds[i].revents) { memset(buff,0,MAX_BUFFER_SIZE); real_read=read(fds[i].fd,buff,MAX_BUFFER_SIZE); if(real_read<0){ printf("Read error!\n"); return 1; } else if (real_read==0) { close(fds[i].fd); fds[i].events=0; } else { if (i==0) { if((buff[0]=='q')||(buff[0]=='Q')) return 0; } else { write(STDOUT_FILENO, buff,real_read); // buff[real_read]='\0'; // printf("%s",buff); } } } } } } return 0; }