fork: Create a new R process using the Unix 'fork' system call

Description Usage Arguments Details Value Author(s) References See Also Examples

Description

Create a new R process using the Unix 'fork' system call.

Usage

1
fork(slave)

Arguments

slave

Function to be executed in the new R process. This can be NULL, see details.

Details

This function provides a thin wrapper around the Unix "fork" system call, which will create a new process which is an exact copy of the current R process, including open files and sockets including STDIN and STDOUT.

The child parameter should normally contain a function to be executed in the newly created process. This function will be called in the new process, and exit() will be called when it returns to terminate the process.

If you wish to explicitly control what happens in the child process, you can pass child=NULL, in which case you are responsible for managing all the details.

First, the child process must call exit() to terminate instead of quit. This is necessary to ensure that temporary files or directories created by the parent process are not removed by the child.

Second, the child process should not attempt to use STDIN to obtain commands since it shares all files open at the time of the fork with the parent. This includes STDIN, consequently, any code following the fork will be be obtained *competitively* by both processes. This usually means that neither process will get a consistent picture of the following commands, since which process gets each line will be simply a matter of which process asked first.

The best way to avoid the second problem is to simply pass a function to fork using the slave parameter. Another way to accomplish this is to ensure that all code that needs to be executed has already been fed to the interpreter before the fork call occurs. The simplest mechinism to achieve this is to wrap the code containing the fork in a code block using curly brackets ({ ... }). This can be a top-level code block, or can be withing a loop or function call.,

To illustrate, this code is a familiar C idiom for forking will NOT be interpreted properly:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  pid = fork(slave=NULL)
      
  if(pid==0) { 
      
    cat("Hi from the child process"); exit() 
      
  } else { 
      
    cat("Hi from the parent process"); 
      
  }

On the other hand, wrapping this code with curly brackets ensures it IS intepreted properly:

1
2
3
4
5
6
7
8
  {
    pid = fork(slave=NULL) 
    if(pid==0) { 
      cat("Hi from the child process\n"); exit() 
    } else {
      cat("Hi from the parent process\n");
    } 
  } 

.

Value

This function returns the process ID of the child process to the parent process. If slave is NULL the function returns 0 to the child process.

Author(s)

Gregory R. Warnes greg@warnes.net

References

'fork' man page

See Also

getpid, exit, wait, kill, killall

Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
###
# Count from 1 to 10 in a separate process
###

# define the function to do the work
testfun <- function()
  {
    cat("Counting in process", getpid(), "\n")
    for(i in 1:10)
      {
        i <<- i+1  # assign into Global environment
        cat("i=",i,"\n")
      }
    cat("Done counting in process", getpid(), "\n")
  }

# run normally, the function will change our value of i
i <- 0
testfun()
i 

# Run in a separate process, our value of i remains unchanged
i <- 0
{
  pid <- fork(testfun)
  wait(pid) # wait until the child finishes, then display its exit status
}
 

###
# Use a socket to communicate between two processes.  Information
# typed on the console, which is read by the initial process, will be send
# to the child process for display. 
###
## Not run: 
send <- function()
  {
     pid <- getpid()
     con1 <- socketConnection(Sys.info()["nodename"], port = 6011)
     i <- 1
     while(TRUE)
       {
         cat("[",pid,"] ",i,": ",sep="")
         data <- readLines(stdin(), n=1)
         writeLines(data, con=con1)
         if( length(grep("quit", data))>0 )
            break;
         i <- i+1
       }
     close(con1)
  }

recieve <- function()
  {
     pid <- getpid()
     con2 <- socketConnection(port = 6011, block=TRUE, server=TRUE)
     i <- 1
     while(TRUE)
       {
          data <- readLines(con2, n=1)
          cat("[",pid,"] ",i,": ",sep="")
          writeLines(data, stdout())
          if( length(grep("quit", data))>0 )
              break;
          i <- i+1
       }
     close(con2)
  }

## Important: if we aren't going to explicitly wait() for the child
## process to exit, we need to set up a dummy signal handler to collect
## (and then throw away) the exit status so that child processes will not
## become zombies when they exit
handleSIGCLD()

# fork off the process
pid <- fork(recieve)

# start sending...
send()

## End(Not run)

## restore SIGCLD signal handling to the previous state
restoreSIGCLD()

warnes/fork documentation built on May 4, 2019, 12:59 a.m.