Processes
This page has been automatically translated using the Google Translate API services. We are working on improving texts. Thank you for your understanding and patience.
A process is a running program that is launched and controlled by the operating system.
Functions
Proc* | bproc_exec (...) |
void | bproc_close (...) |
bool_t | bproc_cancel (...) |
uint32_t | bproc_wait (...) |
bool_t | bproc_finish (...) |
bool_t | bproc_read (...) |
bool_t | bproc_eread (...) |
bool_t | bproc_write (...) |
bool_t | bproc_read_close (...) |
bool_t | bproc_eread_close (...) |
bool_t | bproc_write_close (...) |
void | bproc_exit (...) |
From the programmer perspective, multi-processing is the possibility of launching and interacting with other processes (children) from the main process (parent). The operating system can execute the child process in another CPU core (true multitasking) or in the same as the parent (context switch). This is a system decision in which the programmer can not influence and will depend on the processor type and its workload. The final effect will be that both processes (parent and child) run in parallel.
- Use bproc_exec to launch a new process from the application itself.
- Use bproc_read to read from the standard output of the process.
- Use bproc_write to write to the standard input of the process.
1. Launching processes
bproc_exec will launch a process from our own C program in a similar way as the Terminal does (Figure 1). In this case, the Standard I/O stdin
, stdout
and stderr
will be redirected to the Proc object through anonymous pipes. From here, we can use bproc_write to write on the son stdin
channel and bproc_read to read from his stdout
. The rules of reading/writing are those that govern the operating system pipes and that we can summarize in:
- If the parent calls
bproc_read
and the child has not written anything (empty buffer), the parent will be blocked (wait) until there is information in the child's output channel. - If the child ends and parent is waiting to read,
bproc_read
will returnFALSE
and the parent will continue his execution. - If the parent calls
bproc_write
and the writing buffer is full, the parent will block (wait) until the child reads from hisstdin
and free space in the channel. - If the child ends and the father is blocked by writing,
bproc_write
will returnFALSE
and the parent will continue his execution. - Some commands or processes (eg
sort
) will not start until reading the entirestdin
contents. In these cases, the parent process must use bproc_write_close to indicate to the child that the writing on hisstdin
has finished. - When the parent calls bproc_close, all the I/O channels will be closed and both processes will continue their execution independently. To finish the execution of the child process (kill) use bproc_cancel.
- bproc_wait will stop the parent process until the child completes. To avoid overloading the child output buffer
stdout
, close the channel through bproc_read_close. - bproc_finish will check, in a non-blocking way, if the child has finished running.
2. Multi-processing examples
Let's look at some practical examples of IPC Inter-Process Communication using the standard I/O channels in linked parent-child processes. In (Listing 1) we will dump the child process stdout
output in a file. In (Listing 2) we will redirect both channels, we will write in stdin
and we will read from stdout
using disk files. Finally, we will implement an asynchronous protocol where the parent and child exchange requests and responses. In (Listing 4) we show the code of the child process, in (Listing 3) the parent process and in (Listing 5) the result of the communication, written by the parent process.
stdout
and saving it in a file.
1 2 3 4 5 6 7 8 |
byte_t buffer[512]; uint32_t rsize; File *file = bfile_create("out.txt", NULL); Proc *proc = bproc_exec("dir C:\Windows\System32", NULL); while(bproc_read(proc, buffer, 512, &rsize, NULL) == TRUE) bfile_write(file, buffer, rsize, NULL, NULL); bproc_close(&proc); bfile_close(&file); |
The shell commands are not portable in general. We use them only as an example.
stdin
and stdout
of a process.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
byte_t buffer[512]; uint32_t rsize; File *fsrc = bfile_open("members.txt", ekFILE_READ, NULL); File *fdes = bfile_create("sorted_members.txt", NULL); Proc *proc = bproc_exec("sort", NULL); // Writes to stdin while (bfile_read(fsrc, buffer, 512, &rsize, NULL) == TRUE) bproc_write(proc, buffer, rsize, NULL, NULL); // Closes child stdin bproc_write_close(proc); // Reads child stdout while(bproc_read(proc, buffer, 512, &rsize, NULL) == TRUE) bfile_write(fdes, buffer, rsize, NULL, NULL); bfile_close(&fsrc); bfile_close(&fdes); bproc_close(&proc); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Proc *proc; uint32_t commands[] = { 326, 32, 778, 123, 889, 712, 1, 55, 75, 12 }; uint32_t exit_command = 0; uint32_t i; proc = bproc_exec("child", NULL); for (i = 0; i < 10; ++i) { uint32_t response; uint32_t time; // Send command to child bproc_write(proc, (byte_t*)&commands[i], sizeof(uint32_t), NULL); // Waits for child response bproc_read(proc, (byte_t*)&response, sizeof(uint32_t), NULL); bproc_read(proc, (byte_t*)&time, sizeof(uint32_t), NULL); bstd_printf("Child command %d in %d milliseconds.\n", response, time); } bproc_write(proc, (byte_t*)&exit_command, sizeof(uint32_t), NULL); bproc_close(&proc); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
for (;;) { uint32_t command; // Reads from standard input a command from parent. if (bstd_read((byte_t*)&command, sizeof(command), NULL) == TRUE) { if (command != 0) { // Waits random time (simulates processing). uint32_t timer = bmath_randi(1000, 2000); bthread_sleep(timer); // Writes to standard output the response to parent. bstd_write((const byte_t*)&command, sizeof(command), NULL); bstd_write((const byte_t*)&timer, sizeof(timer), NULL); } else { // Command 0 = Exit break; } } } |
1 2 3 4 5 6 7 8 9 10 |
Child command 326 in 1761 milliseconds. Child command 32 in 1806 milliseconds. Child command 778 in 1989 milliseconds. Child command 123 in 1909 milliseconds. Child command 889 in 1043 milliseconds. Child command 712 in 1153 milliseconds. Child command 1 in 1780 milliseconds. Child command 55 in 1325 milliseconds. Child command 75 in 1157 milliseconds. Child command 12 in 1426 milliseconds. |
bproc_exec ()
Launch a new process.
Proc* bproc_exec(const char_t *command, perror_t *error);
command | The command to execute (path and arguments). Eg. |
error | Error code if the function fails. Can be |
Return
Child process handler that we can use to communicate with him. If the function fails, return NULL
.
Remarks
bproc_close ()
Close communication with the child process and free resources.
void bproc_close(Proc **proc);
proc | Process handler. It will be set to |
Remarks
If the process is still running, this function does not finish it. It only closes the communication channel between the parent and child that will continue to run independently. Like any other object, a process must always be closed, even if it has already finished its execution. Multi-processing examples.
bproc_cancel ()
Force the finalization of the process.
bool_t bproc_cancel(Proc *proc);
proc | Process handler. |
Return
TRUE
if the process is finish. FALSE
otherwise.
bproc_wait ()
Wait until the child process finishes.
uint32_t bproc_wait(Proc *proc);
proc | Process handler. |
Return
The return value of the child process or UINT32_MAX
if there is any error.
bproc_finish ()
Check if the child process is still running.
bool_t bproc_finish(Proc *proc, uint32_t *code);
proc | Process handler. |
code | The output value of the process (if it has finished). Can be |
Return
TRUE
if the child process has finish, FALSE
if not.
Remarks
This function returns immediately. It does not block the process that calls it.
bproc_read ()
Read data from the process standard output (stdout
).
bool_t bproc_read(Proc *proc, byte_t *data, const uint32_t size, uint32_t *rsize, perror_t *error);
proc | Process handler. |
data | Buffer where the read data will be written. |
size | The maximum bytes to read (buffer size). |
rsize | Receive the number of bytes actually read. Can be |
error | Error code if the function fails. Can be |
Return
TRUE
if data has been read. FALSE
if any error has occurred.
Remarks
This function will block the parent process until the child writes in its stdout
. If there is no data in the channel and the child ends, will return FALSE
with rsize = 0
and error = ekPROC_SUCCESS
. Multi-processing examples.
bproc_eread ()
Read data from the process error output (stderr
).
bool_t bproc_eread(Proc *proc, byte_t *data, const uint32_t size, uint32_t *rsize, perror_t *error);
proc | Process handler. |
data | Buffer where the read data will be written. |
size | The maximum bytes to read (buffer size). |
rsize | Receive the number of bytes actually read. Can be |
error | Error code if the function fails. Can be |
Return
TRUE
if data has been read. FALSE
if any error has occurred.
Remarks
This function will block the parent process until the child writes in its stdout
. If there is no data in the channel and the child ends, will return FALSE
with rsize = 0
and error = ekPROC_SUCCESS
. Multi-processing examples.
bproc_write ()
Write data in the process input channel (stdin
).
bool_t bproc_write(Proc *proc, const byte_t *data, const uint32_t size, uint32_t *wsize, perror_t *error);
proc | Process handler. |
data | Buffer that contains the data to write. |
size | The number of bytes to write. |
wsize | It receives the number of bytes actually written. Can be |
error | Error code if the function fails. Can be |
Return
TRUE
if data has been written. FALSE
if any error has occurred.
Remarks
This function will block the parent process if there is no space in the buffer to complete the write. When the child process reads stdin
and free space, the writing will be completed and the parent process will continue its execution. Multi-processing examples.
bproc_read_close ()
Close the stdout
channel of child process.
bool_t bproc_read_close(Proc *proc);
proc | Process handler. |
Return
TRUE
if the channel has been closed. FALSE
if it was already closed.
Remarks
This function allows ignoring the output of the child process, preventing blockages due to channel saturation. Launching processes.
bproc_eread_close ()
Close the stderr
channel of child process.
bool_t bproc_eread_close(Proc *proc);
proc | Process handler. |
Return
TRUE
if the channel has been closed. FALSE
if it was already closed.
Remarks
This function allows ignoring the error output of the child process, preventing blockages due to channel saturation. Launching processes.
bproc_write_close ()
Close the stdin
channel of child process.
bool_t bproc_write_close(Proc *proc);
proc | Process handler. |
Return
TRUE
if the channel has been closed. FALSE
if it was already closed.
Remarks
Some processes need to read all the stdin
content before starting work. When closing the channel, the child process receives the signal EOF
End-Of-File in stdin
. Launching processes.
bproc_exit ()
End the current process (the caller) and all its execution children.
void bproc_exit(const uint32_t code);
code | The exit code of the process. |