⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 975.html

📁 著名的linux英雄站点的文档打包
💻 HTML
📖 第 1 页 / 共 5 页
字号:
<br>
当今Unix系统倾向于使用‘setitimer()’函数实现闹钟,它比简单的‘alarm()’函<br>
数具有更高的分辨率和更多的选择项。一个使用者一般需要首先假设‘alarm()’<br>
和‘setitimer(ITIMER_REAL)’可能是相同的底层计时器,而且假设同时使用两<br>
种方法会造成混乱。<br>
<br>
Itimers可被用于实现一次性或重复信号;而且一般有3种不同的计时器可以用:<br>
<br>
`ITIMER_REAL'<br>
     计数真实(挂钟)时间,然后发送‘SIGALRM’信号<br>
<br>
`ITIMER_VIRTUAL'<br>
     计数进程虚拟(用户中央处理器)时间,然后发送‘SIGVTALRM’信号<br>
<br>
`ITIMER_PROF'<br>
    计数用户和系统中央处理器时间,然后发送‘SIGPROF’信号;它供解释器<br>
    用来进行梗概处理(profiling)<br>
<br>
然而itimers不是许多标准的一部份,尽管它自从4.2BSD就被提供。POSIX实时标<br>
准的扩充定义了类似但不同的函数。<br>
<br>
1.5 父子进程如何通信?<br>
======================<br>
<br>
一对父子进程可以通过正常的进程间通信的办法(管道,套接字,消息队列,共<br>
享内存)进行通信,但也可以通过利用它们作为父子进程的相互关系而具有的一<br>
些特殊方法。<br>
<br>
一个最显然的方法是父进程可以得到子进程的退出状态。<br>
<br>
因为子进程从它的父进程继承文件描述符,所以父进程可以打开一个管道的两端,<br>
然后fork,然后父进程关闭管道这一端,子进程关闭管道另一端。这正是你从你的<br>
进程调用‘popen()’函数运行另一个程序所发生的情况,也就是说你可以向<br>
‘popen()’返回的文件描述符进行写操作而子进程将其当作自己的标准输入,或<br>
者你可以读取这个文件描述符来看子进程向标准输出写了什么。(‘popen()’函数<br>
的mode参数定义你的意图(译者注:mode=“r”为读,mode=“w”为写);如果你<br>
想读写都做,那么你可以并不困难地用管道自己做到)<br>
<br>
而且,子进程继承由父进程用mmap函数映射的匿名共享内存段(或者通过映射特<br>
殊文件‘/dev/zero’);这些共享内存段不能从无关的进程访问。<br>
<br>
1.6 我怎样去除僵死进程?<br>
========================<br>
<br>
1.6.1 何为僵死进程?<br>
--------------------<br>
<br>
当一个程序创建的子进程比父进程提前结束,内核仍然保存一些它的信息以便父<br>
进程会需要它 - 比如,父进程可能需要检查子进程的退出状态。为了得到这些信<br>
息,父进程调用‘wait()’;当这个调用发生,内核可以丢弃这些信息。<br>
<br>
在子进程终止后到父进程调用‘wait()’前的时间里,子进程被称为‘僵死进程’<br>
(‘zombie’)。(如果你用‘ps’,这个子进程会有一个‘Z’出现在它的状态区<br>
里指出这点。)即使它没有在执行,它仍然占据进程表里一个位置。(它不消耗其<br>
它资源,但是有些工具程序会显示错误的数字,比如中央处理器的使用;这是<br>
因为为节约空间进程表的某些部份与会计数据(accounting info)是共用(overlaid)的。)<br>
<br>
这并不好,因为进程表对于进程数有固定的上限,系统会用光它们。即使系统没<br>
有用光 ,每一个用户可以同时执行的进程数有限制,它总是小于系统的限制。<br>
顺便说一下,这也正是你需要总是 检查‘fork()’是否失败的一个原因。<br>
<br>
如果父进程未调用wait函数而终止,子进程将被‘init’进程收管,它将控制子进<br>
程退出后必须的清除工作。(‘init’是一个特殊的系统程序,进程号为1 - 它实际<br>
上是系统启动后运行的第一个程序),<br>
<br>
1.6.2 我怎样避免它们的出现?<br>
----------------------------<br>
<br>
你需要却认父进程为每个子进程的终止调用‘wait()’(或者‘waitpid()’,<br>
‘wait3()’,等等); 或者,在某些系统上,你可以指令系统你对子进程的退出状<br>
态没有兴趣。(译者注:在SysV系统上,可以调用signal函数,设置SIGCLD信号为<br>
SIG_IGN,系统将不产生僵死进程, 详细说明参见&lt;&lt;高级编程&gt;&gt;10.7节)<br>
<br>
另一种方法是*两次*‘fork()’,而且使紧跟的子进程直接退出,这样造成孙子进<br>
程变成孤儿进程(orphaned),从而init进程将负责清除它。欲获得做这个的程序,参<br>
看范例章节的函数‘fork2()’。<br>
<br>
为了忽略子进程状态,你需要做下面的步骤(查询你的系统手册页以知道这是否正<br>
常工作):<br>
<br>
        struct sigaction sa;<br>
        sa.sa_handler = SIG_IGN;<br>
    #ifdef SA_NOCLDWAIT<br>
        sa.sa_flags = SA_NOCLDWAIT;<br>
    #else<br>
        sa.sa_flags = 0;<br>
    #endif<br>
        sigemptyset(&sa.sa_mask);<br>
        sigaction(SIGCHLD, &sa, NULL);<br>
<br>
如果这是成功的,那么‘wait()’函数集将不再正常工作;如果它们中任何一个被<br>
调用,它们将等待直到*所有*子进程已经退出,然后返回失败,并且<br>
‘errno==ECHILD’。<br>
<br>
另一个技巧是捕获SIGCHLD信号,然后使信号处理程序调用‘waitpid()’或<br>
‘wait3()’。参见范例章节的完整程序。<br>
<br>
1.7 我怎样使我的程序作为守护程序运行?<br>
======================================<br>
<br>
一个“守护程序”进程通常被定义为一个后台进程,而且它不属于任何一个终端<br>
会话,(terminal session)。许多系统服务由守护程序实施;如网络服务,打印等。<br>
<br>
简单地在后台启动一个程序并非足够是这些长时间运行的程序;那种方法没有正<br>
确地将进程从启动它的终端脱离(detach)。而且,启动守护程序的普遍接受的的方<br>
法是简单地手工执行或从rc脚本程序执行(译者注:rc:runcom);并希望这个守护<br>
程序将其*自身*安置到后台。<br>
<br>
这里是成为守护程序的步骤:<br>
<br>
 1. 调用‘fork()’以便父进程可以退出,这样就将控制权归还给运行你程序的<br>
    命令行或shell程序。需要这一步以便保证新进程不是一个进程组头领进程(process<br>
    group leader)。下一步,‘setsid()’,会因为你是进程组头领进程而失败。<br>
<br>
 2. 调用‘setsid()’ 以便成为一个进程组和会话组的头领进程。由于一个控制终端<br>
    与一个会话相关联,而且这个新会话还没有获得一个控制终端,我们的进程没<br>
    有控制终端,这对于守护程序来说是一件好事。<br>
<br>
 3. 再次调用‘fork()’所以父进程(会话组头领进程)可以退出。这意味着我们,一<br>
    个非会话组头领进程永远不能重新获得控制终端。<br>
<br>
 4. 调用‘chdir("/")’确认我们的进程不保持任何目录于使用状态。不做这个会导<br>
    致系统管理员不能卸装(umount)一个文件系统,因为它是我们的当前工作目录。<br>
<br>
    [类似的,我们可以改变当前目录至对于守护程序运行重要的文件所在目录]<br>
<br>
 5. 调用‘umask(0)’以便我们拥有对于我们写的任何东西的完全控制。我们不知<br>
    道我们继承了什么样的umask。<br>
<br>
    [这一步是可选的](译者注:这里指步骤5,因为守护程序不一定需要写文件)<br>
<br>
 6. 调用‘close()’关闭文件描述符0,1和2。这样我们释放了从父进程继承的标<br>
    准输入,标准输出,和标准错误输出。我们没办法知道这些文描述符符可能<br>
    已经被重定向去哪里。注意到许多守护程序使用‘sysconf()’来确认<br>
    ‘_SC_OPEN_MAX’的限制。‘_SC_OPEN_MAX’告诉你每个进程能够打<br>
    开的最多文件数。然后使用一个循环,守护程序可以关闭所有可能的文件描<br>
    述符。你必须决定你需要做这个或不做。如果你认为有可能有打开的文件描<br>
    述符,你需要关闭它们,因为系统有一个同时打开文件数的限制。<br>
<br>
 7. 为标准输入,标准输出和标准错误输出建立新的文件描述符。即使你不打算<br>
    使用它们,打开着它们不失为一个好主意。准确操作这些描述符是基于各自<br>
    爱好;比如说,如果你有一个日志文件,你可能希望把它作为标准输出和标<br>
    准错误输出打开,而把‘/dev/null’作为标准输入打开;作为替代方法,你可<br>
    以将‘/dev/console’作为标准错误输出和/或标准输出打开,而‘/dev/null’作<br>
    为标准输入,或者任何其它对你的守护程序有意义的结合方法。(译者注:一<br>
    般使用dup2函数原子化关闭和复制文件描述符,参见&lt;&lt;高级编程&gt;&gt;3.12节)<br>
<br>
如果你的守护程序是被‘inetd’启动的,几乎所有这些步骤都不需要(或不建议<br>
采用)。在那种情况下,标准输入,标准输出和标准错误输出都为你指定为网络<br>
连接,而且‘fork()’的调用和会话的操纵不应做(以免使‘inetd’造成混乱)。只<br>
有‘chdir()’和‘umask()’这两步保持有用。<br>
<br>
1.8  我怎样象ps程序一样审视系统的进程?<br>
=======================================<br>
<br>
你真的不该想做这个。<br>
<br>
到目前为止,移植性最好的是调用‘popen(pscmd,"r")’并处理它的输出。(pscmd<br>
应当是类似SysV系统上的‘“ps -ef”’,BSD系统有很多可能的显示选项:选<br>
择一个。)<br>
<br>
在范例章节有这个问题的两个完整解决方法;一个适用于SunOS 4,它需要root权<br>
限执行并使用‘kvm_*’例程从内核数据结果读取信息;另一种适用于SVR4系统<br>
(包括Sun OS 5),它使用‘/proc’文件系统。<br>
<br>
在具有SVR4.2风格‘/proc’的系统上更简单;只要对于每一个感兴趣的进程号从<br>
文件‘/proc/进程号/psinfo’读取一个psinfo_t结构。但是,这种可能是最清晰的方<br>
法也许又是最不得到很好支持的方法。(在FreeBSD的‘/proc’上,你从<br>
‘/proc/进程号/status’读取一个半未提供文档说明(semi-undocumented)的可打印字<br>
符串;linux有一些与其类似的东西)<br>
<br>
1.9  给定一个进程号,我怎样知道它是个正在运行的程序?<br>
=====================================================<br>
<br>
使用‘kill()’函数,而已0作为信号代码(signal number)。<br>
<br>
从这个函数返回有四种可能的结果:<br>
<br>
  * ‘kill()’返回0<br>
<br>
      - 这意味着一个给定此进程号的进程退出,系统允许你向它发送信号。该进<br>
        程是否可以是僵死进程与不同系统有关。<br>
<br>
  * ‘kill()’返回-1,‘errno == ESRCH’<br>
<br>
      - 要么不存在给定进程号的进程,要么增强的安全机制导致系统否认它的存<br>
        在。(在一些系统上,这个进程有可能是僵死进程。)<br>
<br>
  * ‘kill()’返回-1,‘errno == EPERM’<br>
<br>
      - 系统不允许你杀死(kill)这个特定进程。这意味着要么进程存在(它又可能是<br>
        僵死进程),要么严格的增强安全机制起作用(比如你的进程不允许发送信号<br>
        给*任何人*)。<br>
<br>
   * ‘kill()’返回-1,伴以其它‘errno’值<br>
<br>
      - 你有麻烦了!<br>
<br>
用的最多的技巧是认为调用“成功”或伴以‘EPERM’的“失败”意味着进程存<br>
在,而其它错误意味着它不存在。<br>
<br>
如果你特别为提供‘/proc’文件系统的系统(或所有类似系统)写程序,一个替换<br>
方法存在:检查‘proc/进程号’是否存在是可行的。<br>
<br>
1.10  system函数,pclose函数,waitpid函数 的返回值是什么?<br>
==========================================================<br>
<br>
    ‘system()’,‘pclose()’或者‘waitpid()’的返回值不象是我进程的退出值(exit<br>
       value)(译者注:退出值指调用exit() 或_exit()时给的参数)... 或者退出值左移了8<br>
      位...这是怎么搞的?<br>
<br>
手册页是对的,你也是对的! 如果查阅手册页的‘waitpid()’你会发现进程的返回<br>
值被编码了。正常情况下,进程的返回值在高16位,而余下的位用来作其它事。<br>
如果你希望可移植,你就不能凭借这个,而建议是你该使用提供的宏。这些宏总<br>
是在‘wait()’或‘wstat’的文档中说明了。<br>
<br>
为了不同目的定义的宏(在‘&lt;sys/wait.h&gt;’)包括(stat是‘waitpid()’返回的值):<br>
<br>
`WIFEXITED(stat)'<br>
    如果子进程正常退出则返回非0<br>
<br>
`WEXITSTATUS(stat)'<br>
    子进程返回的退出码<br>
<br>
`WIFSIGNALED(stat)'<br>
    如果子进程由与信号而 终止则返回非0<br>
<br>
`WTERMSIG(stat)'<br>
    终止子进程的信号代码<br>
<br>
`WIFSTOPPED(stat)'<br>
    如果子进程暂停(stopped)则返回非0<br>
<br>
`WSTOPSIG(stat)'<br>
    使子进程暂停的信号代码<br>
<br>
`WIFCONTINUED(stat)'<br>
    如果状态是表示子进程继续执行则返回非0<br>
<br>
`WCOREDUMP(stat)'<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -