Вы должны использовать рабочий поток, который ожидает события из основного потока и обрабатывает их. Это длинный ответ, и во избежание его увеличения я опущу проверку ошибок, хотя она противоречит шестой заповеди .
Структура задачи и очередь
Создайте структуру, которая задает задачу. Я буду использовать общие функции get_task
и push_task
. В реальном примере следует использовать поточную очередь tasks
, но это бесполезно усложнит ответ. Я набросал это только из старых программ, которые лежали вокруг.
struct task {
/* function callback */
void (*fun)(void *);
/* parameter to pass to callback */
void *arg;
};
Синхронизация
Используйте мьютекс, чтобы защитить очередь задач, и семафор, чтобы сигнализировать, что работа должна быть сделана. Пожалуйста, посмотрите, что я написал выше жирным шрифтом.
/* this has to be initialized in main */
sem_t sem;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
Рабочая функция
Рабочая функция просто ждет и выполняет задачи, когда ей говорят.
static void *worker(void *arg)
{
struct task t;
/* detach */
pthread_detach(pthread_self());
/* loop forever */
while (1) {
/* block until we have work to do */
sem_wait(&sem);
/* we've got work to do */
pthread_mutex_lock(&mtx);
/* get the task */
t = get_task();
pthread_mutex_unlock(&mtx);
/* we are safe now, nobody can touch t */
/* execute the callback - here is your function pointer*/
(*t.fun)(t.arg);
}
return NULL;
}
Основная функция
Роль главной функции - инициализация вещей и выполнение задач.
pthread_t t1;
/* initialize unnamed semaphore */
sem_init(&sem, 0, 0);
/* start worker thread */
if (0 != pthread_create(&t1, NULL, worker, NULL)) {
perror("pthread_create");
exit(1);
}
Задачи нажатия
На этом этапе рабочий поток ожидает задачи, которые вы можете отправить из основного.
pthread_mutex_lock(&mtx);
push_task(my_task);
pthread_mutex_unlock(&mtx);
Как этот сервер узнает, что клиент запускает события? Вам решать, есть много способов сделать IPC в Unix. Я предлагаю использовать очередь сообщений .
Пример очереди сообщений сервера
#define MSGSIZE 1024
int main()
{
mqd_t mq;
struct mq_attr attr;
char message[MSGSIZE];
int read_bytes;
attr.mq_maxmsg = 10;
attr.mq_msgsize = MSGSIZE;
mq = mq_open("/queue", O_RDWR | O_CREAT, 0700, &attr);
if ((mqd_t)-1 == mq) {
perror("mq_open");
exit(1);
}
while (1) {
/* get message from queue */
read_bytes = mq_receive(mq, message, MSGSIZE, NULL);
if (-1 == read_bytes) {
perror("mq_receive");
exit(1);
}
/* do what you wish with the message */
}
}
Таким образом, в части «делай, что хочешь» вы можете вызвать интерпретацию типа события и выдать его за работника. Отправка сообщения от клиента тривиально похожа, поэтому я не буду публиковать это (если вы действительно не можете это сделать, просто спросите).
Это всего лишь (возможно, сломанные) кусочки одной большой головоломки. Ваша задача собрать их во все, что вы строите.