Chinaunix

标题: linux c编程,有办法把事件或者内容发给指定的子进程吗? [打印本页]

作者: joint    时间: 2006-10-16 18:40
标题: linux c编程,有办法把事件或者内容发给指定的子进程吗?
父进程生成4个子进程,要把连接请求发给指定的第4个子进程,有办法不?
作者: langue    时间: 2006-10-16 18:42
先 listen,accept 到了以后 fork 出去
作者: joint    时间: 2006-10-16 18:53
谢谢楼上

想先prefork几个child出来,父进程得到连接后,把内容发给子进程去处理
作者: joint    时间: 2006-10-16 18:57
24.6.2 Signaling Another Process

The kill function can be used to send a signal to another process. In spite of its name, it can be used for a lot of things other than causing a process to terminate. Some examples of situations where you might want to send signals between processes are:

    * A parent process starts a child to perform a task—perhaps having the child running an infinite loop—and then terminates the child when the task is no longer needed.
    * A process executes as part of a group, and needs to terminate or notify the other processes in the group when an error or other event occurs.
    * Two processes need to synchronize while working together.

This section assumes that you know a little bit about how processes work. For more information on this subject, see Processes.

The kill function is declared in signal.h.
— Function: int kill (pid_t pid, int signum)

    The kill function sends the signal signum to the process or process group specified by pid. Besides the signals listed in Standard Signals, signum can also have a value of zero to check the validity of the pid.

    The pid specifies the process or process group to receive the signal:

    pid > 0
        The process whose identifier is pid.
    pid == 0
        All processes in the same process group as the sender.
    pid < -1
        The process group whose identifier is −pid.
    pid == -1
        If the process is privileged, send the signal to all processes except for some special system processes. Otherwise, send the signal to all processes with the same effective user ID.

    A process can send a signal to itself with a call like kill (getpid(), signum). If kill is used by a process to send a signal to itself, and the signal is not blocked, then kill delivers at least one signal (which might be some other pending unblocked signal instead of the signal signum) to that process before it returns.

    The return value from kill is zero if the signal can be sent successfully. Otherwise, no signal is sent, and a value of -1 is returned. If pid specifies sending a signal to several processes, kill succeeds if it can send the signal to at least one of them. There's no way you can tell which of the processes got the signal or whether all of them did.

    The following errno error conditions are defined for this function:

    EINVAL
        The signum argument is an invalid or unsupported number.
    EPERM
        You do not have the privilege to send a signal to the process or any of the processes in the process group named by pid.
    ESCRH
        The pid argument does not refer to an existing process or group.

— Function: int killpg (int pgid, int signum)

    This is similar to kill, but sends signal signum to the process group pgid. This function is provided for compatibility with BSD; using kill to do this is more portable.

As a simple example of kill, the call kill (getpid (), sig) has the same effect as raise (sig).
作者: joint    时间: 2006-10-16 18:58
24.8.3 Using sigsuspend

The clean and reliable way to wait for a signal to arrive is to block it and then use sigsuspend. By using sigsuspend in a loop, you can wait for certain kinds of signals, while letting other kinds of signals be handled by their handlers.
— Function: int sigsuspend (const sigset_t *set)

    This function replaces the process's signal mask with set and then suspends the process until a signal is delivered whose action is either to terminate the process or invoke a signal handling function. In other words, the program is effectively suspended until one of the signals that is not a member of set arrives.

    If the process is woken up by delivery of a signal that invokes a handler function, and the handler function returns, then sigsuspend also returns.

    The mask remains set only as long as sigsuspend is waiting. The function sigsuspend always restores the previous signal mask when it returns.

    The return value and error conditions are the same as for pause.

With sigsuspend, you can replace the pause or sleep loop in the previous section with something completely reliable:

     sigset_t mask, oldmask;
     
     ...
     
     /* Set up the mask of signals to temporarily block. */
     sigemptyset (&mask);
     sigaddset (&mask, SIGUSR1);
     
     ...
     
     /* Wait for a signal to arrive. */
     sigprocmask (SIG_BLOCK, &mask, &oldmask);
     while (!usr_interrupt)
       sigsuspend (&oldmask);
     sigprocmask (SIG_UNBLOCK, &mask, NULL);

This last piece of code is a little tricky. The key point to remember here is that when sigsuspend returns, it resets the process's signal mask to the original value, the value from before the call to sigsuspend—in this case, the SIGUSR1 signal is once again blocked. The second call to sigprocmask is necessary to explicitly unblock this signal.

One other point: you may be wondering why the while loop is necessary at all, since the program is apparently only waiting for one SIGUSR1 signal. The answer is that the mask passed to sigsuspend permits the process to be woken up by the delivery of other kinds of signals, as well—for example, job control signals. If the process is woken up by a signal that doesn't set usr_interrupt, it just suspends itself again until the “right” kind of signal eventually arrives.

This technique takes a few more lines of preparation, but that is needed just once for each kind of wait criterion you want to use. The code that actually waits is just four lines.
作者: todaygood    时间: 2006-10-16 19:00
什么意思?
作者: joint    时间: 2006-10-16 19:03
程序开始先fork几个子进程,然后子进程等待父进程给他发消息。父进程获得信息后,把内容发给空闲的某个子进程
作者: langue    时间: 2006-10-16 19:05
1、在启动的时候 fork 一下,原进程退出,新进程变 daemon(为了后来的进程不变僵尸);
2、在 daemon 进程里 bind、listen,然后 accept;
3、接到连接,立即 fork。主进程返回、继续 accept,子进程处理连接,然后退出;
4、循环第 3 步

上面的是传统 fork 模型。apache httpd 中使用了 prefork,通过锁来实现逐个 accept
作者: joint    时间: 2006-10-16 19:21
原帖由 langue 于 2006-10-16 19:05 发表
1、在启动的时候 fork 一下,原进程退出,新进程变 daemon(为了后来的进程不变僵尸);
2、在 daemon 进程里 bind、listen,然后 accept;
3、接到连接,立即 fork。主进程返回、继续 accept,子进程处理连接, ...


1,2,3,4我略知一二,呵呵,新手,不知道那个kill(), suspend效率如何,apache那个prefork锁控制比较麻烦,小程序,不敢搞那么大,还不懂那原理呢,再找找资料看看。。。
作者: joint    时间: 2006-10-16 19:22
多谢 langue 女侠
作者: langue    时间: 2006-10-16 19:24
原帖由 joint 于 2006-10-16 19:21 发表


1,2,3,4我略知一二,呵呵,新手,不知道那个kill(), suspend效率如何,apache那个prefork锁控制比较麻烦,小程序,不敢搞那么大,还不懂那原理呢,再找找资料看看。。。


你要 kill suspend 干什么?子进程自己退出。另外忘了说,父进程里要把 SIGCHLD 给屏蔽。
作者: joint    时间: 2006-10-16 19:25
原帖由 langue 于 2006-10-16 19:24 发表


你要 kill suspend 干什么?子进程自己退出。另外忘了说,父进程里要把 SIGCHLD 给屏蔽。

kill可以发送结束之外的消息啊
作者: joint    时间: 2006-10-16 19:31
回家了,回去再上来看,呵呵
作者: langue    时间: 2006-10-16 19:34
原帖由 joint 于 2006-10-16 19:25 发表

kill可以发送结束之外的消息啊


用发送信号的方式好像太麻烦了,要是信号处理不好,会有危险。



至于 file descriptor 传递的问题,你可以看看 APUE 第二版 17.4 节,passing file descriptors。
通过这样的方法,可以在进程间传递文件描述符。
作者: joint    时间: 2006-10-16 20:27
再请问langue,频繁fork效率如何?一个频繁的客户端请求环境,数据量不大,但是会有几千千个客户端,频繁的发送UDP数据包
作者: langue    时间: 2006-10-17 06:01
效率问题……我没有那样的测试环境(主要是没有那样的同时多源地址多连接数),所以也不好说。

但我知道,fork 的效率,和 prefork 没什么区别;区别主要在于,fork 模型在大量连接流刚到来的时候,肯定
比 prefork 的慢。fork 很耗资源,所以几秒钟以后就基本没区别了。

觉得慢,可以尝试 POSIX threads,或者用 select、poll 模型。select 一类的可以单线程、单进程实现。

P.S.
很小的数据量,大量的请求,无论是 fork,还是 prefork、pthread,都不值。

另外记住一句话:1/10 的代码执行,花费了 9/10 的 cpu 时间。
作者: joint    时间: 2006-10-17 08:46
谢谢langue,俺找找你说的资料,先学习去,有问题再来请教




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2