Asynchronous Programming

Both JavaScript and C support asynchronous programming models, which look similar to each other with respect to their usage. The following example shows, on a very high level, how async code looks like in JavaScript:

async function printDelayed(message, cancellationToken) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    return `Message: ${message}`;
}

C code is structured differently:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h> // Requires GCC
#include <unistd.h>

void* printDelayed(void* args) {
    char* message = (char*)args;
    sleep(1); // Simulating a delay of 1 second
    char* result = malloc(strlen(message) + 10); // Allocating memory for the result
    sprintf(result, "Message: %s", message);
    return result;
}

int main() {
    char* message = "Hello, World!";
    pthread_t tid;
    void* result;

    pthread_create(&tid, NULL, printDelayed, (void*)message);
    pthread_join(tid, &result);

    printf("%s\n", (char*)result);
    free(result); // Freeing allocated memory
    return 0;
}

See also:

Executing tasks

From the following example the PrintDelayed method executes, even though it is not awaited:

let cancellationToken = undefined; 
printDelayed("message", cancellationToken); // Prints "message" after a second.
await new Promise(resolve => setTimeout(resolve, 2000));

async function printDelayed(message, cancellationToken) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    console.log(message);
}

In C:

#include <stdio.h>

#ifdef _WIN32
#include <windows.h>
#define sleep(x) Sleep(x * 1000)
#else
#include <unistd.h>
#endif

void printDelayed(char* message) {
    sleep(1); // Delay for 1 second
    printf("%s\n", message);
}

int main() {
    char* message = "message";
    printDelayed(message); // Prints "message" after a second.
    sleep(2); // Delay for 2 seconds
    return 0;
}

Task cancellation

The previous JavaScript examples included passing a CancellationToken to asynchronous methods, as is considered best practice in JavaScript. CancellationTokens can be used to abort an asynchronous operation.

In C language, the concept ofcancellation can be implemented using custom structures and functions.

Executing multiple Tasks

In JavaScript, Promise.race is frequently used to handle the execution of multiple tasks.

Promise.race completes as soon as any task completes.

const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

const delayMessage = async (delayTime) => {
    await delay(delayTime);
    return `Waited ${delayTime / 1000} second(s).`;
};

const delay1 = delayMessage(1000);
const delay2 = delayMessage(2000);

Promise.race([delay1, delay2]).then(result => {
    console.log(result); // Output: Waited 1 second(s).
});

In C, to achieve similar functionality to Promise.race in JavaScript, one can use a combination of threads and synchronization mechanisms like mutexes or semaphores. By creating multiple threads that perform tasks concurrently and using synchronization to determine which thread finishes first, a similar behavior to Promise.race can be achieved in C. Below is a simplified example in C:

#include <stdio.h>
#include <pthread.h> // Requires GCC
#include <unistd.h>

void* delayMessage(void* delayTime) {
    int ms = *((int*)delayTime);
    usleep(ms * 1000); // Convert milliseconds to microseconds
    char* message = malloc(100 * sizeof(char));
    sprintf(message, "Waited %d second(s).", ms / 1000);
    return message;
}

int main() {
    pthread_t thread1, thread2;
    int delay1 = 1000;
    int delay2 = 2000;
    char* result1;
    char* result2;

    pthread_create(&thread1, NULL, delayMessage, (void*)&delay1);
    pthread_create(&thread2, NULL, delayMessage, (void*)&delay2);

    pthread_join(thread1, (void**)&result1);
    pthread_join(thread2, (void**)&result2);

    printf("%s\n", result1); // Output: Waited 1 second(s).

    free(result1);
    free(result2);

    return 0;
}

Multiple consumers

In JavaScript a Promise can be used across multiple consumers. All of them can await the task and get notified when the task is completed or failed.

In C:

#include <stdio.h>
#include <stdlib.h>

#ifdef _WIN32
#include <windows.h> // For Sleep(), DWORD
#else
#include <unistd.h> // For sleep()
#include <sys/types.h> // For pid_t
#include <sys/wait.h> // For wait()
#endif

void background_operation() {
#ifdef _WIN32
    Sleep(2000);
#else
    sleep(2);
#endif
    printf("Background operation completed.\n");
}

#ifdef _WIN32
BOOL WINAPI signal_handler(DWORD dwCtrlType) {
    if (dwCtrlType == CTRL_C_EVENT) {
        printf("Signal received. Cancelling background operation.\n");
        exit(0);
    }
    return TRUE;
}
#else
void signal_handler(int signal) {
    if (signal == SIGINT) {
        printf("Signal received. Cancelling background operation.\n");
        exit(0);
    }
}
#endif

int main() {
#ifdef _WIN32
    SetConsoleCtrlHandler(signal_handler, TRUE);
#else
    signal(SIGINT, signal_handler);
#endif

    DWORD pid = GetCurrentProcessId(); // Get current process ID
    printf("Process ID: %lu\n", pid);

    // Fork and perform background operation
    // ...

    wait(NULL);
    printf("Parent process waiting for child process to finish.\n");

    return 0;
}

Asynchronous iteration

C does not yet have an API for asynchronous iteration in the standard library.

In JavaScript, writing async iterators has comparable syntax to when writing synchronous iterators:

async function* RangeAsync(start, count) {
    for (let i = 0; i < count; i++) {
        await new Promise(resolve => setTimeout(resolve, i * 1000));
        yield start + i;
    }
}

(async () => {
    for await (const item of RangeAsync(10, 3)) {
        console.log(item + " "); // Prints "10 11 12".
    }
})();

In C:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

typedef struct {
    int start;
    int count;
} Range;

void RangeAsync(Range range) {
    for (int i = 0; i < range.count; i++) {
        usleep(i * 1000000); // Simulating async delay in microseconds
        printf("%d ", range.start + i);
    }
}

int main() {
    Range range = {10, 3};
    RangeAsync(range);
    return 0;
}