Traduzione equivalente del comportamento asincrono in C

1

Come follow-up di my altra domanda , se si dovesse costruire un traduttore generico da una lingua che ha supporto (sia con una libreria esterna o altro) per un comportamento asincrono a un linguaggio che può o meno supportare nativamente (usiamola C come esempio), quindi è una traduzione semanticamente equivalente di un callback asincrono per richiamare semplicemente la funzione di callback prima di tornare / completare dal successore? Nota che nell'esempio che seguo mi riferisco a JavaScript come linguaggio che supporta il comportamento asincrono anche se non supporta nativamente il comportamento asincrono, ma in pratica viene usato frequentemente attraverso alcune librerie.

Ad esempio, dato il seguente programma JavaScript (da questo semplice esempio di una funzione JavaScript asincrona )

window.setTimeout(function() {
    console.log("World");
}, 1000);
console.log("Hello");

sarebbe una traduzione semanticamente equivalente di quanto sopra per usare fork in quanto sopra tale che il processo figlio dorme per 1000 millisecondi e quindi invoca le stampe "World" a stdout , e nel processo genitore continua con la stampa "Hello" a stdout ? Ci sono problemi con questa traduzione specifica? Ciò comporta problemi di traduzione nel caso generale?

Si noti che la mia motivazione è trovare un modo per implementare un comportamento asincrono, non affidare l'implementazione dell'implementazione all'uso di una libreria.

    
posta Francesco Gramano 29.04.2015 - 00:45
fonte

1 risposta

1

Ecco un programma che implementa un codice simile in C. Si noti che ho rimosso tutto il controllo degli errori per brevità:

#include <sys/timerfd.h>
#include <stdlib.h>
#include <sys/epoll.h>

static int pending_jobs;
static int efd;
struct cb_data {
    int fd;
    void (*fn)(void);
};

static void set_timeout(void (*fn)(void), int secs)
{
    struct epoll_event ev;
    int fd;
    struct itimerspec sleep_time;
    struct timespec now;
    struct cb_data *d;

    /* Setup a timer */
    clock_gettime(CLOCK_REALTIME, &now);

    sleep_time.it_value.tv_sec = now.tv_sec + secs;
    sleep_time.it_value.tv_nsec = now.tv_nsec;
    sleep_time.it_interval.tv_sec = 0;
    sleep_time.it_interval.tv_nsec = 0;

    fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK);
    timerfd_settime(fd, TFD_TIMER_ABSTIME, &sleep_time, NULL);

    /* Add it to epoll */
    ev.events = EPOLLIN;
    d = malloc(sizeof(*d));
    d->fd = fd;
    d->fn = fn;
    ev.data.ptr = d;
    pending_jobs++;
    epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);

}

static void main_program_loop(void)
{
    /* Loop around epoll wait until there are no more jobs */
    while (pending_jobs > 0) {
        struct epoll_event events[10];
        int n, nfds;
        nfds = epoll_wait(efd, events, 10, -1);
        for (n = 0; n < nfds; ++n) {
            struct cb_data *d = events[n].data.ptr;
            epoll_ctl(efd, EPOLL_CTL_DEL, d->fd, NULL);
            pending_jobs--;
            close(d->fd);
            d->fn();
            free(d);
        }

    }
    /* No more jobs pending, exit */
}

void print_world(void)
{
    puts("World");
}

int main(void)
{
    pending_jobs = 0;
    efd = epoll_create1(0);

    /* The JS equivalent */
    set_timeout(print_world, 1);
    puts("hello");

    /* loop until all pending events are done */
    main_program_loop();

    close(efd);
}

Puoi vedere che la C equivalente allo snippet di javascript è:

void print_world(void)
{
    puts("World");
}
...
set_timeout(print_world, 1);
puts("hello");

Quindi è abbastanza vicino. Tutto il resto è la strumentazione necessaria in C e Javascript. Tranne che in Javascript, è incluso nel motore. In C, puoi eseguire il rollover (qualcosa di simile al programma precedente), o usare una libreria come libev o libevent.

    
risposta data 01.05.2015 - 07:00
fonte

Leggi altre domande sui tag