如何在unix中使用fork()?为什么不使用fork(pointerToFunctionToRun)形式的东西? [英] How to use fork() in unix? Why not something of the form fork(pointerToFunctionToRun)?

查看:123
本文介绍了如何在unix中使用fork()?为什么不使用fork(pointerToFunctionToRun)形式的东西?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在理解如何使用Unix的fork()时遇到了一些麻烦.当需要并行化时,我习惯于在应用程序中生成线程.总是这样的形式

CreateNewThread(MyFunctionToRun());

void myFunctionToRun() { ... }

现在,当学习Unix的fork()时,给出了以下形式的示例:

fork();
printf("%d\n", 123);

其中分叉后的代码被拆分".我不明白fork()如何有用.为什么fork()的语法与上面的CreateNewThread()相似,在其中您要向其传递要运行的函数的地址?

要完成类似于CreateNewThread()的操作,我必须要有创造力,并要做类似的事情

//pseudo code
id = fork();

if (id == 0) { //im the child
    FunctionToRun();
} else { //im the parent
    wait();
}

可能的问题是,我习惯于以.NET方式生成线程,所以我对此并不清楚.我在这里想念什么? fork()CreateNewThread()有什么优势?

PS:我知道fork()将产生一个新的进程,而CreateNewThread()将产生一个新的线程.

谢谢

解决方案

fork()说:将当前进程状态复制到新进程中,然后从此处开始运行."因为代码随后在两个进程中运行,所以实际上它返回两次:一次在父进程中(返回子进程的进程标识符),一次在子进程中(返回零).

fork()之后子进程中可以安全调用的内容有很多限制(请参见下文).期望fork()调用是生成运行具有自己状态的新可执行文件的新进程的一部分.此过程的第二部分是对execve()或其变体之一的调用,它指定要加载到当前正在运行的进程中的可执行文件的路径,要提供给该进程的参数以及包围该可执行文件的环境变量.过程. (没有什么可以阻止您重新执行当前正在运行的可执行文件,并提供一个标志,使它在您真正想要的位置从父级中断的地方继续执行.)

UNIX fork()-exec()的舞步大致等同于Windows CreateProcess().较新的功能更像:posix_spawn().

作为使用fork()的实际示例,请考虑一个shell,例如bash. fork()始终由命令外壳使用.当您告诉外壳程序运行某个程序(例如echo "hello world")时,它会分叉自身,然后执行该程序.管道是分叉进程的集合,其中父级在fork()exec()之间适当地装配了stdoutstdin.

如果要创建新线程,则应使用Posix线程库.您使用pthread_create()创建一个新的Posix线程(pthread).您的CreateNewThread()示例如下所示:

#include <pthread.h>

/* Pthread functions are expected to accept and return void *. */ 
void *MyFunctionToRun(void *dummy __unused);

pthread_t thread;
int error = pthread_create(&thread,
        NULL/*use default thread attributes*/,
        MyFunctionToRun,
        (void *)NULL/*argument*/);

在线程可用之前,fork()是UNIX提供给多线程的最接近的东西.现在线程可用了,fork()的使用几乎完全限于产生新进程来执行不同的可执行文件.

下面的

:限制是因为fork()早于多线程,因此只有调用fork()的线程才能在子进程中继续执行.根据 POSIX :

应使用单个线程创建一个进程.如果多线程进程调用fork(),则新进程应包含调用线程及其整个地址空间的副本,其中可能包括互斥体和其他资源的状态.因此,为避免错误,子进程只能执行异步信号安全操作,直到调用exec函数之一为止. [THR] [Option Start]可以通过pthread_atfork()函数来建立Fork处理程序,以便在fork()调用之间维护应用程序不变式. [选项结束]

当应用程序从信号处理程序调用fork()时,并且pthread_atfork()注册的任何fork处理程序调用的函数都不是异步信号安全的,则行为未定义.

由于您调用的任何库函数都可能代表您生成了一个线程,因此偏执的假设是,您始终仅限于在调用fork()exec()的子进程中执行异步信号安全操作. /p>

I am having some trouble understanding how to use Unix's fork(). I am used to, when in need of parallelization, spawining threads in my application. It's always something of the form

CreateNewThread(MyFunctionToRun());

void myFunctionToRun() { ... }

Now, when learning about Unix's fork(), I was given examples of the form:

fork();
printf("%d\n", 123);

in which the code after the fork is "split up". I can't understand how fork() can be useful. Why doesn't fork() have a similar syntax to the above CreateNewThread(), where you pass it the address of a function you want to run?

To accomplish something similar to CreateNewThread(), I'd have to be creative and do something like

//pseudo code
id = fork();

if (id == 0) { //im the child
    FunctionToRun();
} else { //im the parent
    wait();
}

Maybe the problem is that I am so used to spawning threads the .NET way that I can't think clearly about this. What am I missing here? What are the advantages of fork() over CreateNewThread()?

PS: I know fork() will spawn a new process, while CreateNewThread() will spawn a new thread.

Thanks

解决方案

fork() says "copy the current process state into a new process and start it running from right here." Because the code is then running in two processes, it in fact returns twice: once in the parent process (where it returns the child process's process identifier) and once in the child (where it returns zero).

There are a lot of restrictions on what it is safe to call in the child process after fork() (see below). The expectation is that the fork() call was part one of spawning a new process running a new executable with its own state. Part two of this process is a call to execve() or one of its variants, which specifies the path to an executable to be loaded into the currently running process, the arguments to be provided to that process, and the environment variables to surround that process. (There is nothing to stop you from re-executing the currently running executable and providing a flag that will make it pick up where the parent left off, if that's what you really want.)

The UNIX fork()-exec() dance is roughly the equivalent of the Windows CreateProcess(). A newer function is even more like it: posix_spawn().

As a practical example of using fork(), consider a shell, such as bash. fork() is used all the time by a command shell. When you tell the shell to run a program (such as echo "hello world"), it forks itself and then execs that program. A pipeline is a collection of forked processes with stdout and stdin rigged up appropriately by the parent in between fork() and exec().

If you want to create a new thread, you should use the Posix threads library. You create a new Posix thread (pthread) using pthread_create(). Your CreateNewThread() example would look like this:

#include <pthread.h>

/* Pthread functions are expected to accept and return void *. */ 
void *MyFunctionToRun(void *dummy __unused);

pthread_t thread;
int error = pthread_create(&thread,
        NULL/*use default thread attributes*/,
        MyFunctionToRun,
        (void *)NULL/*argument*/);

Before threads were available, fork() was the closest thing UNIX provided to multithreading. Now that threads are available, usage of fork() is almost entirely limited to spawning a new process to execute a different executable.

below: The restrictions are because fork() predates multithreading, so only the thread that calls fork() continues to execute in the child process. Per POSIX:

A process shall be created with a single thread. If a multi-threaded process calls fork(), the new process shall contain a replica of the calling thread and its entire address space, possibly including the states of mutexes and other resources. Consequently, to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called. [THR] [Option Start] Fork handlers may be established by means of the pthread_atfork() function in order to maintain application invariants across fork() calls. [Option End]

When the application calls fork() from a signal handler and any of the fork handlers registered by pthread_atfork() calls a function that is not asynch-signal-safe, the behavior is undefined.

Because any library function you call could have spawned a thread on your behalf, the paranoid assumption is that you are always limited to executing async-signal-safe operations in the child process between calling fork() and exec().

这篇关于如何在unix中使用fork()?为什么不使用fork(pointerToFunctionToRun)形式的东西?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆