Сигналы и обратные вызовы в C? - PullRequest
1 голос
/ 02 февраля 2012

Есть ли способ создания обратных вызовов и сигналов в C?

Конечно, я могу использовать указатель на функцию, но я хочу создать сигнал, который может содержать несколько функций, то есть может связывать несколько событий. Что-то вроде boost.signals но в Си. Есть ли какой-либо способ?

Есть много библиотек графического интерфейса в C, которые используют обратные вызовы, как они достигают этого?

Ответы [ 2 ]

4 голосов
/ 02 февраля 2012

Простое решение - сохранить список функций для вызова, а в обработчике сигналов просто выполнить итерацию по этому списку, вызывая каждую функцию.

Примерно так:

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

typedef void (*event_callback_t)();

struct event_handler_node
{
    event_callback_t callback;
    struct event_handler_node *next;
};

void add_event_handler(struct event_handler_node **list_head,
                       event_callback_t callback)
{
    struct event_handler_node *node = malloc(sizeof(struct event_handler_node));

    node->callback = callback;
    if (*list_head != NULL)
        node->next = *list_head;
    *list_head = node;
}

void call_all_event_handlers(struct event_handler_node *list_head)
{
    struct event_handler_node *node;

    for (node = list_head; node != NULL; node = node->next)
    {
        (*node->callback)();
    }
}

struct event_handler_node *signal_callbacks = NULL;
void signal_handler(int signum)
{
    call_all_event_handlers(signal_callbacks);
}

void my_callback()
{
    printf("Hello from callback!\n");
}

int main()
{
    /* Add a callback to the list */
    add_event_handler(&signal_callbacks, my_callback);

    /* Set signal handler for a signal */
    signal(SIGUSR1, signal_handler);

    /* Invoke the signal handler */
    kill(getpid(), SIGUSR1);

    return 1;
}

Примечание: Нет обработки ошибок и освобождения выделенной памяти. Это оставлено в качестве упражнения для читателя. : -)

3 голосов
/ 02 февраля 2012

Как сказал Иоахим, вы должны сохранить список указателей функций.В C нет встроенного динамического массива, но вы можете реализовать его самостоятельно:

struct list {
 void (*func)(void);
 struct list *next;
} *cb=NULL;
void add_callback(void (*f)(void)) {
 struct list *newCallback=(struct list *)malloc(sizeof(struct list));
 newCallback->func=f;
 newCallback->next=cb;
 cb=newCallback;
}
void call_callbacks() {
 struct list *t=cb;
 while (t) {
  (*(t->func))();
  t=t->next;
 }
}
...