Unix编程常见问题解答.doc_第1页
Unix编程常见问题解答.doc_第2页
Unix编程常见问题解答.doc_第3页
Unix编程常见问题解答.doc_第4页
Unix编程常见问题解答.doc_第5页
已阅读5页,还剩73页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Unix编程常见问题解答 作者:HopeCao 发表时间:2002/10/09 10:56amUnix编程常见问题解答(FAQ / Frequently Asked Questions)(v1.37)(中文版 v0.1.0) 关于这篇“常见问题解答”* 这篇“常见问题解答” 由Patrick Horgan自一九九六年五月开始起草;因其历经数月未复更新,我从而接手编辑。我已经将其内容稍做重新安排并加入一些新的内容;我仍然认为它仍处于“有待开发建设”中。 请将批评,建议,增补,更正或其它意见发给维护者,电子邮件地址:andrewerlenstar.demon.co.uk 这篇文档的超文本版(英文)在WEB上可以获得。主站点设在“http:/www.erlenstar.demon.co.uk/unix/faq_toc.html”。美国镜像站点设在“/unix/faq_toc.html”。 这篇文档可以用FTP的方式自主机和其众多镜像站点的news.answers 归档中找到(译者注:URL是/pub/faqs/unix-faq/programmer/faq)。它的官方归档名是“unix-faq/programmer/faq”。其他将网络新闻组*.answers归档的服务器也会在目录“grammer”下存放这篇文档。 其他信息资源未于此一一列出。读者可在新闻组grammer每周定期发布的READ ME FIRST中找到其他“常见问题”,书籍,原代码等资源的的连接。关于管理新闻组的小问题等等也能在其中找到;而我只想在将这篇文档中特别讨论问题和回答。 所有提供的资料已经经过维护者编辑,所有错误或疏忽是我的责任,跟提供者无关。 这篇“常见问题解答”现在以Texinfo资源格式维护;我使用“makeinfo”程序将其转换成供新闻组阅读的原始字符文件格式,并使用“texi2html”程序将其转换成HTML格式。 版权所有:1997,1998, 1999, 2000 Andrew Gierth. 这篇文档允许通过新闻组或电子邮件方式的分发,也允许在news.answers 归档的镜像FTP或WWW站点归档存放,并保证提供所有维持该文档更新应付出的努力。(本许可能够以个人为单位取消)未经维护者许可,不允许将该文档以其他任何方式发表,无论是书面,WWW,光盘,或在其他任何媒体。 内容提供者名单,无先后次序: Andrew Gierth Patrick J. Horgan withheldStephen Baynes James Raynard withheldMichael F. Quigley withheldKen Pizzini withheldThamer Al-Herbish withheldNick Kew Dan Abarbanel withheldBilly Chambless Walter Briscoe Jim Buchanan Dave Plonka Daniel Stenberg withheldRalph Corderoy Stuart Kemp withheldSergei Chernev Bjorn Reese withheldJoe Halpin Aaron Crane Geoff Clare -Edward Jiang Zhen Yao 问题目录* (译者:这里我有意保留原文以便于查询) 1. Process Control 进程控制1.1 Creating new processes: fork() 创建新进程:fork函数 1.1.1 What does fork() do? fork函数干什么? 1.1.2 Whats the difference between fork() and vfork()? fork函数 与 vfork函数的区别在哪里? 1.1.3 Why use _exit rather than exit in the child branch of a fork? 为何在一个fork的子进程分支中使用_exit函数而不使用exit函数?1.2 Environment variables 环境变量 1.2.1 How can I get/set an environment variable from a program? 我怎样在程序中获得/设置环境变量? 1.2.2 How can I read the whole environment? 我怎样读取整个环境变量表?1.3 How can I sleep for less than a second? 我怎样睡眠小于一秒?1.4 How can I get a finer-grained version of alarm()? 我怎样得到一个更细分时间单位的alarm函数版本(译者注:希望alarm的时间小于一秒)?1.5 How can a parent and child process communicate? 父子进程如何通信?1.6 How do I get rid of zombie processes? 我怎样去除僵死进程? 1.6.1 What is a zombie? 何为僵死进程? 1.6.2 How do I prevent them from occuring? 我怎样避免它们的出现?1.7 How do I get my program to act like a daemon? 我怎样使我的程序作为守护程序运行?1.8 How can I look at process in the system like ps does? 我怎样象ps程序一样审视系统的进程?1.9 Given a pid, how can I tell if its a running program? 给定一个进程号(译者注:pid: process ID),我怎样知道它是个正在运行的程序?1.10 Whats the return value of system/pclose/waitpid? system函数,pclose函数,waitpid函数 的返回值是什么?1.11 How do I find out about a process memory usage? 我怎样找出一个进程的存储器使用情况?1.12 Why do processes never decrease in size? 为什么进程的大小不缩减?1.13 How do I change the name of my program (as seen by ps)? 我怎样改变我程序的名字(即“ps”看到的名字)?1.14 How can I find a process executable file? 我怎样找到进程的相应可执行文件? 1.14.1 So where do I put my configuration files then? 那么,我把配置文件放在哪里呢?1.15 Why doesnt my process get SIGHUP when its parent dies? 为何父进程死时,我的进程未得到SIGHUP信号?1.16 How can I kill all descendents of a process? 我怎样杀死一个进程的所有派生进程? 2. General File handling (including pipes and sockets) 一般文件操作(包括管道和套接字)2.1 How to manage multiple connections? 怎样管理多个连接? 2.1.1 How do I use select()? 我怎样使用select()? 2.1.2 How do I use poll()? 我怎样使用poll() ? 2.1.3 Can I use SysV IPC at the same time as select or poll? 我是否可以将SysV 进程间通信 (译者注:IPC: Interprocess Communications) 与select或poll同时使用?2.2 How can I tell when the other end of a connection shuts down? 我怎么知道连接的另一端已关闭?2.3 Best way to read directories? 读目录的最好方法?2.4 How can I find out if someone else has a file open? 我怎么知道其他人已经打开一个文件?2.5 How do I lock a file? 我怎样锁定一个文件?2.6 How do I find out if a file has been updated by another process? 我怎么知道一个文件是否已被其他进程更新?2.7 How does the du utility work? “du”工具程序是怎么工作的?2.8 How do I find the size of a file? 我怎么知道一个文件的大小?2.9 How do I expand in a filename like the shell does? 我怎样象shell程序一样将一个文件名中含有的“”展开?2.10 What can I do with named pipes (FIFOs)? 我能用有名管道(FIFOs)(译者注:FIFO: First In First Oout)干什么? 2.10.1 What is a named pipe? 什么是有名管道? 2.10.2 How do I create a named pipe? 我怎样创建一个有名管道? 2.10.3 How do I use a named pipe? 我怎样使用一个有名管道? 2.10.4 Can I use a named pipe across NFS? 我能基于网络文件系统(译者注:NFS:Network File System)使用有名管道吗? 2.10.5 Can multiple processes write to the pipe simultaneously? 多个进程能否同时向这个管道写执行写操作? 2.10.6 Using named pipes in applications 在应用程序中使用有名管道。 3. Terminal I/O 终端输入/输出(I/O:input/output)3.1 How can I make my program not echo input? 我怎样使我的程序不回射输入?3.2 How can I read single characters from the terminal? 我怎样从终端读取单个字符?3.3 How can I check and see if a key was pressed? 我怎样检查是否一个键被摁下?3.4 How can I move the cursor around the screen? 我怎样将光标在屏幕里移动?3.5 What are pttys? pttys(pttys:Pseudo-teletypes)是什么?3.6 How to handle a serial port or modem? 怎样控制一个串行口和调制解调器(译者注:modem: modulate-demodulate) 3.6.1 Serial device names and types 串行设备和类型 3.6.2 Setting up termios flags 设置termios的标志位 c_iflag c_oflag c_cflag c_lflag c_cc 4. System Information 系统信息4.1 How can I tell how much memory my system has? 我怎样知道我的系统有多少存储器容量?4.2 How do I check a users password? 我怎样检查一个用户的口令? 4.2.1 How do I get a users password? 我怎样得到一个用户的口令? 4.2.2 How do I get shadow passwords by uid? 我怎样通过用户号(译者注:uid: User ID)得到阴影口令文件中的口令? 4.2.3 How do I verify a users password? 我怎样核对一个用户的口令? 5. Miscellaneous programming 编程杂技5.1 How do I compare strings using wildcards? 我怎样使用通配字符比较字符串? 5.1.1 How do I compare strings using filename patterns? 我怎样使用文件名通配模式比较字符串? 5.1.2 How do I compare strings using regular expressions? 我怎样使用正则表达式比较字符串?5.2 Whats the best way to send mail from a program? 什么是在程序中发送电子邮件的最好方法? 5.2.1 The simple method: /bin/mail 简单方法:/bin/mail 5.2.2 Invoking the MTA directly: /usr/lib/sendmail 直接启动邮件传输代理(译者注:MTA: mail transfer agent):/usr/bin/sendmail Supplying the envelope explicitly 显式提供收件人信息 Allowing sendmail to deduce the recipients 允许sendmail程序根据邮件内容分析出收件人 6. Use of tools 工具的使用6.1 How can I debug the children after a fork? 我怎样调试fork函数产生的子进程?6.2 How to build library from other libraries? 怎样通过其他库文件建立新的库文件?6.3 How to create shared libraries / dlls? 怎样创建动态连接库/dlls?6.4 Can I replace objects in a shared library? 我能更改一个动态连接库里的目标吗?6.5 How can I generate a stack dump from within a running program? 我能在一个运行着的程序中生成堆栈映象吗? 1. 进程控制* 1.1 创建新进程:fork函数= 1.1.1 fork函数干什么?- #include #include pid_t fork(void); fork()函数用于从已存在进程中创建一个新进程。新进程称为子进程,而原进程称为父进程。你可以通过检查fork()函数的返回值知道哪个是父进程,哪个是子进程。父进程得到的返回值是子进程的进程号,而子进程则返回0。以下这个范例程序说明它的基本功能: pid_t pid; switch (pid = fork() case -1: /* 这里pid为-1,fork函数失败 */ /* 一些可能的原因是 */ /* 进程数或虚拟内存用尽 */ perror(The fork failed!); break; case 0: /* pid为0,子进程 */ /* 这里,我们是孩子,要做什么? */ /* . */ /* 但是做完后, 我们需要做类似下面: */ _exit(0); default: /* pid大于0,为父进程得到的子进程号 */ printf(Childs pid is %dn,pid); 当然,有人可以用if() . else .语句取代switch()语句,但是上面的形式是一个有用的惯用方法。 知道子进程自父进程继承什么或未继承什么将有助于我们。下面这个名单会因为不同Unix的实现而发生变化,所以或许准确性有了水份。请注意子进程得到的是这些东西的 *拷贝*,不是它们本身。 由子进程自父进程继承到: * 进程的资格(真实(real)/有效(effective)/已保存(saved) 用户号(UIDs)和组号(GIDs) * 环境(environment) * 堆栈 * 内存 * 打开文件的描述符(注意对应的文件的位置由父子进程共享,这会引起含糊情况) * 执行时关闭(close-on-exec) 标志 (译者注:close-on-exec标志可通过fnctl()对文件描 述符设置,POSIX.1要求所有目录流都必须在exec函数调用时关闭。更详细说明, 参见 W. R. Stevens, 1993, 尤晋元等译(以下简称), 3.13节和8.9节) * 信号(signal)控制设定 * nice值 (译者注:nice值由nice函数设定,该值表示进程的优先级,数值越小,优 先级越高) * 进程调度类别(scheduler class) (译者注:进程调度类别指进程在系统中被调度时所 属的类别,不同类别有不同优先级,根据进程调度类别和nice值,进程调度程序可计 算出每个进程的全局优先级(Global process prority),优先级高的进程优先执行) * 进程组号 * 对话期ID(Session ID) (译者注:译文取自,指:进程所属的对话期 (session)ID, 一个对话期包括一个或多个进程组, 更详细说明参见 9.5节) * 当前工作目录 * 根目录 (译者注:根目录不一定是“/”,它可由chroot函数改变) * 文件方式创建屏蔽字(file mode creation mask (umask) (译者注:译文取自,指:创建新文件的缺省屏蔽字) * 资源限制 * 控制终端 子进程所独有: * 进程号 * 不同的父进程号(译者注:即子进程的父进程号与父进程的父进程号不同,父进 程号可由getppid函数得到) * 自己的文件描述符和目录流的拷贝(译者注:目录流由opendir函数创建,因其为 顺序读取,顾称“目录流”) * 子进程不继承父进程的进程,正文(text),数据和其它锁定内存(memory locks) (译者注:锁定内存指被锁定的虚拟内存页,锁定后,不允许内核将其在必要时 换出(page out),详细说明参见 2.2版, 1999, 3.4.2节) * 在tms结构中的系统时间(译者注:tms结构可由times函数获得,它保存四个数据 用于记录进程使用中央处理器(CPU:Central Processing Unit)的时间,包括:用户时 间,系统时间,用户各子进程合计时间,系统各子进程合计时间) * 资源使用(resource utilizations)设定为0 * 阻塞信号集初始化为空集(译者注:原文此处不明确,译文根据fork函数手册页 稍做修改) * 不继承由timer_create函数创建的计时器 * 不继承异步输入和输出 1.1.2 fork函数 与 vfork函数的区别在哪里里?- 有些系统有一个系统调用vfork(),它最初被设计成fork()的较少额外支出(lower-overhead)版本。因为fork()包括拷贝整个进程的地址空间,所以非常“昂贵”,这个vfork()函数因此被引入。(在3.0BSD中)(译者注:BSD:Berkeley Software Distribution) *但是*,自从vfork()被引入,fork()的实现方法得到了很大改善,最值得注意的是“写操作时拷贝”(copy-on-write)的引入,它是通过允许父子进程可访问相同物理内存从而伪装(fake)了对进程地址空间的真实拷贝,直到有进程改变内存中数据时才拷贝。这个提高很大程度上抹杀了需要vfork()的理由;事实上,一大部份系统完全丧失了vfork()的原始功能。但为了兼容,它们仍然提供vfork()函数调用,但它只是简单地调用fork(),而不试图模拟所有vfork()的语义(semantics, 译文取自,指定义的内容和做法)。 结论是,试图使用任何fork()和vfork()的不同点是*很*不明智的。事实上,可能使用vfork()根本就是不明智的,除非你确切知道你想*干什么*。 两者的基本区别在于当使用vfork()创建新进程时,父进程将被暂时阻塞,而子进程则可以借用父进程的地址空间。这个奇特状态将持续直到子进程要么退出,要么调用execve(),至此父进程才继续执行。 这意味着一个由vfork()创建的子进程必须小心以免出乎意料地改变父进程的变量。特别的,子进程必须不从包含vfork()调用的函数返回,而且必须不调用exit()(如果它需要退出,它需要使用_exit();事实上,对于使用正常fork()创建的子进程这也是正确的)(译者注:参见1.1.3) 1.1.3 为何在一个fork的子进程分支中使用_exit函数而不使用exit函数?- exit()与_exit()有不少区别在使用fork(),特别是vfork()时变得很突出。 exit()与_exit()的基本区别在于前一个调用实施与调用库里用户状态结构(user-mode constructs)有关的清除工作(clean-up),而且调用用户自定义的清除程序(译者注:自定义清除程序由atexit函数定义,可定义多次,并以倒序执行),相对应,后一个函数只为进程实施内核清除工作。 在由fork()创建的子进程分支里,正常情况下使用exit()是不正确的,这是因为使用它会导致标准输入输出(译者注:stdio: Standard Input Output)的缓冲区被清空两次,而且临时文件被出乎意料的删除(译者注:临时文件由tmpfile函数创建在系统临时目录下,文件名由系统随机生成)。在C+程序中情况会更糟,因为静态目标(static objects)的析构函数(destructors)可以被错误地执行。(还有一些特殊情况,比如守护程序,它们的*父进程*需要调用_exit()而不是子进程;适用于绝大多数情况的基本规则是,exit()在每一次进入main函数后只调用一次。) 在由vfork()创建的子进程分支里,exit()的使用将更加危险,因为它将影响*父*进程的状态。 1.2 环境变量= 1.2.1 如何从程序中获得/设置环境变量?-获得一个环境变量可以通过调用getenv()函数完成。 #include char *getenv(const char *name); 设置一个环境变量可以通过调用putenv()函数完成。 #include int putenv(char *string); 变量string应该遵守name=value的格式。已经传递给putenv函数的字符串*不*能够被释放或变成无效,因为一个指向它的指针将由putenv()保存。这意味着它必须是在静态数据区中或是从堆(heap)分配的。如果这个环境变量被另一个putenv()的调用重新定义或删除,上述字符串可以被释放。 /* 译者增加: 因为putenv()有这样的局限,在使用中经常会导致一些错误,GNU libc 中还包括了两个BSD风格的函数:#include int setenv(const char *name, const char *value, int replace);void unsetenv(const char *name); setenv()/unsetenv()函数可以完成所有putenv()能做的事。setenv() 可以不受指针限制地向环境变量中添加新值,但传入参数不能为空(NULL)。当replace为0时,如果环境变量中已经有了name项,函数什么也不做(保留原项),否则原项被覆盖。unsetenv()是用来把name项从环境变量中删除。注意:这两个函数只存在在BSD和GNU库中,其他如SunOS系统中不包括它们,因此将会带来一些兼容问题。我们可以用getenv()/putenv()来实现: int setenv(const char *name, const char *value, int replace) char *envstr; if (name = NULL | value = NULL) return 1; if (getenv(name) !=NULL) envstr = (char *) malloc(strlen(name) + strlen(value) + 2); sprintf (envstr, %s=%s, name, value); if (putenv(envstr); return 1; return 0;*/ 记住环境变量是被继承的;每一个进程有一个不同的环境变量表拷贝(译者注:从core文件中我们可以看出这一点)。结果是,你不能从一个其他进程改变当前进程的环境变量,比如shell进程。 假设你想得到环境变量TERM的值,你需要使用下面的程序: char *envvar; envvar=getenv(TERM); printf(The value for the environment variable TERM is ); if(envvar) printf(%sn,envvar); else printf(not set.n); 现在假设你想创建一个新的环境变量,变量名为MYVAR,值为MYVAL。以下是你将怎样做: static char envbuf256; sprintf(envbuf,MYVAR=%s,MYVAL); if(putenv(envbuf) printf(Sorry, putenv() couldnt find the memory for %sn,envbuf); /* Might exit() or something here if you cant live without it */ 1.2.2 我怎样读取整个环境变量表?- 如果你不知道确切你想要的环境变量的名字,那么getenv()函数不是很有用。在这种情况下,你必须更深入了解环境变量表的存储方式。 全局变量,char *envrion,包含指向环境字符串指针数组的指针,每一个字符串的形式为“NAME=value”(译者注:和putenv()中的“string”的格式相同)。这个数组以一个空(NULL)指针标记结束。这里是一个打印当前环境变量列表的小程序(类似printenv)。 #include extern char *environ; int main() char *ep = environ; char *p; while (p = *ep+) printf(%sn, p); return 0; 一般情况下,envrion变量作为可选的第三个参数传递给main();就是说,上面的程序可以写成: #include int main(int argc, char *argv, char *envp) char *p; while (p = *envp+) printf(%sn, p); return 0; 虽然这种方法被广泛的操纵系统所支持(译者注:包括DOS),这种方法事实上并没有被POSIX(译者注:POSIX: Portable Operating System Interace)标准所定义。(一般的,它也比较没用) 1.3 我怎样睡眠小于一秒?= 在所有Unix中都有的sleep()函数只允许以秒计算的时间间隔。如果你想要更细化,那么你需要寻找替换方法: * 许多系统有一个usleep()函数 * 你可以使用select()或poll(),并设置成无文件描述符并试验;一个普 遍技巧是基于其中一个函数写一个usleep()函数。(参见comp.unix.questions FAQ 的一些例子) * 如果你的系统有itimers(很多是有的)(译者注:setitimer和getitimer是两个操作 itimers的函数,使用“man setitimer”确认你的系统支持),你可以用它们自己撺一 个usleep()。(参见BSD源程序的usleep()以便知道怎样做) * 如果你有POSIX实时(realtime)支持,那会有一个nanosleep()函数。 众观以上方法,select()可能是移植性最好的(直截了当说,它经常比usleep()或基于itimer的方法更有效)。但是,在睡眠中捕获信号的做法会有所不同;基于不同应用,这可以成为或不成为一个问题。 无论你选择哪条路,意识到你将受到系统计时器分辨率的限制是很重要的(一些系统允许设置非常短的时间间隔,而其他的系统有一个分辨率,比如说10毫秒,而且总是将所有设置时间取整到那个值)。而且,关于sleep(),你设置的延迟只是最小值(译者注:实际延迟的最小值);经过这段时间的延迟,会有一个中间时间间隔直到你的进程重新被调度到。 1.4 我怎样得到一个更细分时间单位的alarm函数版本?= 当今Unix系统倾向于使用setitimer()函数实现闹钟,它比简单的alarm()函数具有更高的分辨率和更多的选择项。一个使用者一般需要首先假设alarm()和setitimer(ITIMER_REAL)可能是相同的底层计时器,而且假设同时使用两种方法会造成混乱。 Itimers可被用于实现一次性或重复信号;而且一般有3种不同的计时器可以用: ITIMER_REAL 计数真实(挂钟)时间,然后发送SIGALRM信号 ITIMER_VIRTUAL 计数进程虚拟(用户中央处理器)时间,然后发送SIGVTALRM信号 ITIMER_PROF 计数用户和系统中央处理器时间,然后发送SIGPROF信号;它供解释器 用来进行梗概处理(profiling) 然而itimers不是许多标准的一部份,尽管它自从4.2BSD就被提供。POSIX实时标准的扩充定义了类似但不同的函数。 1.5 父子进程如何通信?= 一对父子进程可以通过正常的进程间通信的办法(管道,套接字,消息队列,共享内存)进行通信,但也可以通过利用它们作为父子进程的相互关系而具有的一些特殊方法。 一个最显然的方法是父进程可以得到子进程的退出状态。 因为子进程从它的父进程继承文件描述符,所以父进程可以打开一个管道的两端,然后fork,然后父进程关闭管道这一端,子进程关闭管道另一端。这正是你从你的进程调用popen()函数运行另一个程序所发生的情况,也就是说你可以向popen()返回的文件描述符进行写操作而子进程将其当作自己的标准输入,或者你可以读取这个文件描述符来看子进程向标准输出写了什么。(popen()函数的mode参数定义你的意图(译者注:mode=“r”为读,mode=“w”为写);如果你想读写都做,那么你可以并不困难地用管道自己做到) 而且,子进程继承由父进程用mmap函数映射的匿名共享内存段(或者通过映射特殊文件/dev/zero);这些共享内存段不能从无关的进程访问。 1.6 我怎样去除僵死进程?= 1.6.1 何为僵死进程?- 当一个程序创建的子进程比父进程提前结束,内核仍然保存一些它的信息以便父进程会需要它 - 比如,父进程可能需要检查子进程的退出状态。为了得到这些信息,父进程调用wait();当这个调用发生,内核可以丢弃这些信息。 在子进程终止后到父进程调用wait()前的时间里,子进程被称为僵死进程(zombie)。(如果你用ps,这个子进程会有一个Z出现在它的状态区里指出这点。)即使它没有在执行,它仍然占据进程表里一个位置。(它不消耗其它资源,但是有些工具程序会显示错误的数字,比如中央处理器的使用;这是因为为节约空间进程表的某些部份与会计数据(accounting info)是共用(overlaid)的。) 这并不好,因为进程表对于进程数有固定的上限,系统会用光它们。即使系统没有用光 ,每一个用户可以同时执行的进程数有限制,它总是小于系统的限制。顺便说一下,这也正是你需要总是 检查fork()是否失败的一个原因。 如果父进程未调用wait函数而终止,子进程将被init进程收管,它将控制子进程退出后必须的清除工作。(init是一个特殊的系统程序,进程号为1 - 它实际上是系统启动后运行的第一个程序), 1.6.2 我怎样避免它们的出现?- 你需要却认父进程为每个子进程的终止调用wait()(或者waitpid(),wait3(),等等); 或者,在某些系统上,你可以指令系统你对子进程的退出状态没有兴趣。(译者注:在SysV系统上,可以调用signal函数,设置SIGCLD信号为SIG_IGN,系统将不产生僵死进程, 详细说明参见10.7节) 另一种方法是*两次*fork(),而且使紧跟的子进程直接退出,这样造成孙子进程变成孤儿进程(orphaned),从而init进程将负责清除它。欲获得做这个的程序,参看范例章节的函数fork2()。 为了忽略子进程状态,你需要做下面的步骤(查询你的系统手册页以知道这是否正常工作): struct sigaction sa; sa.sa_handler = SIG_IGN; #ifdef SA_NOCLDWAIT sa.sa_flags = SA_NOCLDWAIT; #else sa.sa_flags = 0; #endif sigemptyset(&sa.sa_mask); sigaction(SIGCHLD, &sa, NULL); 如果这是成功的,那么wait()函数集将不再正常工作;如果它们中任何一个被调用,它们将等待直到*所有*子进程已经退出,然后返回失败,并且errno=ECHILD。 另一个技巧是捕获SIGCHLD信号,然后使信号处理程序调用waitpid()或wait3()。参见范例章节的完整程序。 1.7 我怎样使我的程序作为守护程序运行?= 一个“守护程序”进程通常被定义为一个后台进程,而且它不属于任何一个终端会话,(terminal session)。许多系统服务由守护程序实施;如网络服务,打印等。 简单地在后台启动一个程序并非足够是这些长时间运行的程序;那种方法没有正确地将进程从启动它的终端脱离(detach)。而且,启动守护程序的普遍接受的的方法是简单地手工执行或从rc脚本程序执行(译者注:rc:runcom);并希望这个守护程序将其*自身*安置到后台。 这里是成为守护程序的步骤: 1. 调用fork()以便父进程可以退出,这样就将控制权归还给运行你程序的 命令行或shell程序。需要这一步以便保证新进程不是一个进程组头领进程(process group leader)。下一步,setsid(),会因为你是进程组头领进程而失败。 2. 调用setsid() 以便成为一个进程组和会话组的头领进程。由于一个控制终端 与一个会话相关联,而且这个新会话还没有获得一个控制终端,我们的进程没 有控制终端,这对于守护程序来说是一件好事。 3. 再次

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论