Linux应用编程

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

• wait() 系统调用:父进程等待子进程撤销 若子进程尚未撤销,父进程睡眠等待,子进程撤销时,将其唤醒; 若子进程已撤销,父进程不睡眠等待。 main() { int i; if (fork()) { /*父进程*/ i=wait(); printf("It is parent process.\n"); printf("The child process,ID number %d, is finished.\n",i); } else{ /*子进程*/ printf("It is child process.\n"); } }
进程标识号
1) 进程的最知名的属性就是它的进程号(prosess ID, PID) 和它的父进程号(parent process ID, PPID). 2) 进程号是非零正整数 3) 所有进程追溯其祖先最终都会落到进程号为1的进程身上, 这个进程叫做 init进程。 init进程是内核自举后第一个启动的进程。 init引导系统、启动守护 进程并且运行必要的程序。 init是所有进程的父进程 PID的常见用法 1) 创建惟一的文件名或目录。 例如, 当调用getpid后, 进程接着要用PID创 建一个临时文件。 2) 把PID写入日志文件作为日志消息的一部分, 以清楚说明是哪个进程记录 下的日志消息 3) 可以用它的PPID向它的父进程发送信号或其他信息 #include <stdio.h> #include <unistd.h> #include <stdlib.h> int main(void) { printf("PID = %d \n", getpid()); printf("PPID = %d \n", getppid()); exit(EXIT_SUCCESS); }
创建子进程: int fork() 返回值:-1:创建子进程失败 0: 子进程得到的返回值 >0:父进程得到的返回值,表示子进程号(pid) 创建子进程后,父、子进程执行同一个程序,子进程继承父 进程的资源。 Main() { int i; i=fork(); if(i) { 父进程执行的程序;} else { 子进程执行的程序;} 父、子进程都执行的程序; }
•Sleep(n)系统调用 :进程睡眠等待 n 秒。 • Exit () 系统调用:调用者进程终止;若父进程因wait()而睡眠, 则 唤醒父进程。 main() { int i; if (fork()) { /*父进程*/ sleep(10); printf("It is parent process.\n"); i=wait(); printf("The child process,ID number %d, is finished.\n",i); } else{ /*子进程*/ printf("It is child process.\n"); exit(); } }
3. 2 进程间通信
IPC(InterProcess Communication)
IPC类型




管道 FIFO(命名管道) 消息队列 信号量 共享空间 套接口 (可用于多台主机间的进程间通信 )
管道
特点: 半双工,即数据只能在一个方向上流动

只能在具有公共祖先的进程之间使用。通 常,一个管道由一进程调用fork,此后父、 子进程之间就可应用该管道
Linux应用编程
3.1 linux进程控制
一个进程是一个正在执行的程序的实例,也是Linux基本的 调度单位
正在运行的程序的一个进程由如下元素组成 1) 程序的当前上下文(context), 它是程序当前执行的状态 2) 程序的当前执行目录 3) 程序访问的文件和目录 4) 程序的信任状态(credentials)或说访问权限, 比如它的 文件模式和所有权 5) 内存和其他分配给进程的系统资源 轻量级进程, 也称为线程, 提供了独立的执行线索和堆 栈段,但却共享数据段, Linux特有的_clone调用用于支持 线程,它通过指定共享的属性带来了更好的灵活性

当管道的一端被关闭后,下列规则起作用: 1) 当读一个写端已被关闭的管道时,在所有 数据都被读取后,read返回0,以指示达到 了文件结束处。 2)如果写一个读端已被关闭的管道,则产生 信号SIGPIPE。如果忽略该信号或者捕捉该 信号并从其处理程序返回,则write出错返回, errno设置为EPIPE。
系统调用pipe函数创建管道 #include <unistd.h> int pipe(int filedes[2]); 返回:若成功则为0,若出错则为-1 经由参数filedes返回两个文件描述符,filedes[0] 为读而打开,filedes[1]为写而打开。filedes[1] 的输出是filedes[0]的输入。
/*创建子进程的实验。子进程修改了公共变量globa和私有变量vari。 */ #include<stdio.h> #include<sys/types.h> #include<unistd.h> int globa=4; int main() { pid_t pid; int vari=5; printf("before fork.\n"); if ((pid=fork())<0) {printf("fork error.\n"); exit(0); } else if(pid==0) {globa++; vari--; printf("Child changed the vari and globa.\n");} else printf("Parent did not changed the vari and globa.\n"); printf("globa=%d, vari=%d\n",globa,vari);
下面是一个父进程通过管道向子进程传送数据的程序例子。 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <linux/limits.h> main() { int n, fd[2]; pid_t pid; char line[PIPE_BUF]; if (pipe(fd) < 0) { perror("pipe error"); exit(1); } if ( (pid=fork()) < 0) { perror("fork error"); exit(1); } else if (pid > 0) { // parent close(fd[0]); write(fd[1], "hello world\n", 12); } else { // child close(fd[1]); n = read(fd[0], line, PIPE_BUF); write(STDOUT_FILENO, line, n); } exit(0); }
main() { int i; if (fork()) { /*父进程*/ printf("It is parent process.\n"); printf("The child process,ID number is %d.\n",i); } else { /*子进程*/ printf("It is child process.\n"); } } 程序执行结果:显示器上输出三行, 但三行内容的次序不确定。

在上面的例子中,直接对管道描述符调用read和 write。 在写管道时,常数PIPE_BUF规定了内核中管道缓 存器的大小。如果对管道进行write调用,而且要 求写的字节数小于等于PIPE_BUF,则此操作不会 与其他进程对同一管道(或FIFO)的write操作穿 插进行。但是,若有多个进程同时写一个管道 (或FIFO),而且某个或某些进程要求写的字节 数超过PIPE_BUF字节数,则数据可能会与其他写 操作的数据相穿插。
调用pipe的进程接着调用fork,这样就创建 了从父进程到子进程或反之的IPC通道。
fork之后做什么取决于我们想要有的数据流 的方向。对于从父进程到子进程的管道,父 进程关闭管道的读端(fd[0]),子进程则关 闭写端(fd[1])。对于从子进程到父进程的 管道,父进程关闭fd[1],子进程关闭fd[0]。
•Exec( 参数)系统调用:执行一个文件的调用; 放弃原来执行的程序和数据区, 以调用进程提供的参数转去执 行这个新的程序(进程的身份不变)。 例:简化的shell程序: #incluse <stdio.h> main() {char command[32]; char * prompt = “$”; while (printf(“%s”,prompt),gets(command) != NULL) {if(fork() == 0) execlp(command,(char *) 0); else if (前台执行) wait(); } }
•进程通信 管道 (pipe系统调用) pipe(fd): 创建一个管道,fd[0]为管道的读端;fd[1]为管道的写端。 管道可用来实现父进程与其子孙进程之间的通信。管道以FIFO方 式传送消息。 例: #include >stdio.h> main() { int x,fd[2]; char buf[30],s[30]; pipe(fd); /*创建管道*/ while(x=fork() = = -1); /*创建子进程失败时,循环*/ if(x = = 0) { sprintf(buf,“This is an example\n”); write(fd[1],buf,30); /*把buf中的字符写入管道*/ exit(0); } wait(); read(fd[0],s,30); /*父进程读管道中的字符*/ printf(“%s”,s); }
FIFO


FIFO又称为命名管道。管道只能由相关进 程使用,它们共同的祖先进程创建了管道。 但是,通过FIFO,不相关的进程也能交换 数据。 FIFO是一种文件类型。stat结构成员 st_mode的编码指明文件是否是FIFO类型。 可以用S_ISFIFO宏对此进行测试。创建 FIFO类似于创建文件。FIFO的路径名确实 存在于文件系统中。
•软中断通信:(UNIX中的用于同一用户间的低级通信)。 目的是通知接收进程发生了异步事件。) UNIX SYSTEM V 中定义了19个软中断信号; LINUX中定义了31个软中断信号 (在signal.h中定义) kill(pid,signal): 向进程pid发送信号signal,若pid进程在可中断的优 先级(低优先级)上睡眠,则将其唤醒。 signal(sig,ps): 设置sig号软中断信号的处理方式; 三种处理方式:SIG_DFL:系统默认方式,一般是终止进程; SIG_IGN:忽略(屏蔽); func(): 用制定义函数func()处理。 Signal设置的处理方式,仅一次有效,处理后即回到默认方式。 9(SIGKILL)号软中断不允许设置。 getpid()系统调用:返回本进程的进程号。 getppid()系统调用:返回父进程的进程号。
include <signal.h> func() {printf(“A signal has been processed\n”);} main() { int i; signal(SIGUSR1,func); if (fork()) { /*父进程*/ sleep(10); printf("It is parent process.\n"); i=wait(); printf("The child process,ID number %d, is finished.\n",i); } else{ /*子进程*/ printf("It is child process.\n"); kill(gwk.baidu.comtppid(),SIGUSER1); exit(); } }
相关文档
最新文档