Cross-platform C SDK logo

Cross-platform C SDK

Processes

❮ Back
Next ❯
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 (...)
voidbproc_close (...)
bool_tbproc_cancel (...)
uint32_tbproc_wait (...)
bool_tbproc_finish (...)
bool_tbproc_read (...)
bool_tbproc_eread (...)
bool_tbproc_write (...)
bool_tbproc_read_close (...)
bool_tbproc_eread_close (...)
bool_tbproc_write_close (...)
voidbproc_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:

Schema of a parent process and a child process linked by the Proc object.
Figure 1: Launching a process from our own C code.
  • 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 return FALSE 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 his stdin and free space in the channel.
  • If the child ends and the father is blocked by writing, bproc_write will return FALSE and the parent will continue his execution.
  • Some commands or processes (eg sort) will not start until reading the entire stdin contents. In these cases, the parent process must use bproc_write_close to indicate to the child that the writing on his stdin 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.

Listing 1: Reading from a 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.
Listing 2: Redirecting the 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);
Listing 3: Asynchronous protocol (parent process).
 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);
Listing 4: Asynchronous protocol (child process).
 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;
        }
    }
}
Listing 5: Parent process execution result.
 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. "ls -lh" or "C:\Programs\imgresize background.png -w640 -h480".

error

Error code if the function fails. Can be NULL.

Return

Child process handler that we can use to communicate with him. If the function fails, return NULL.

Remarks

Multi-processing examples.


bproc_close ()

Close communication with the child process and free resources.

void
bproc_close(Proc **proc);
proc

Process handler. It will be set to NULL after closing.

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 NULL.

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 NULL.

error

Error code if the function fails. Can be NULL.

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 NULL.

error

Error code if the function fails. Can be NULL.

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 NULL.

error

Error code if the function fails. Can be NULL.

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.

❮ Back
Next ❯