Necesito portar una aplicación multiproceso que use las funciones de la API de Windows SetEvent , CreateEvent y WaitForMultipleObjects a Linux. He encontrado muchos hilos relacionados con este problema, pero ninguno de ellos proporcionó una solución razonable para mi problema.
Tengo una aplicación que se bifurca en tres procesos y administra el grupo de trabajadores de subprocesos de un proceso a través de estos Eventos.
Tuve múltiples soluciones a este problema. Una era crear archivos especiales FIFO en Linux usando mkfifo en Linux y usar una declaración de selección para activar los subprocesos. El problema es que esta solución funcionará de manera diferente a WaitForMultipleObjects . Por ejemplo, si 10 subprocesos del grupo de trabajadores esperarán el evento y llamo a SetEvent cinco veces, exactamente cinco subprocesos de trabajo se activarán y harán el trabajo, al usar la variante FIFO en Linux, despertaría cada subproceso, que i en la selección estado de cuenta y esperando que los datos se introduzcan en el fifo. La mejor manera de describir esto es que la API de Windows funciona como un semáforo global con un conteo de uno.
También pensé en usar pthreads y condition variables para recrear esto y compartir las variables a través de la memoria compartida ( shm_open y mmap ), ¡pero me encuentro con el mismo problema aquí!
¿Cuál sería una forma razonable de recrear este comportamiento en Linux? Encontré algunas soluciones haciendo esto dentro de un solo proceso, pero ¿qué hay de hacerlo entre múltiples procesos?
Cualquier idea es apreciada (Nota: no espero una implementación completa, solo necesito algunas ideas más para comenzar con este problema).
Podría usar un semáforo ( sem_init ), funcionan en memoria compartida. También hay semáforos con nombre ( sem_open ) si desea inicializarlos desde diferentes procesos. Si necesita intercambiar mensajes con los trabajadores, por ejemplo , para pasarles las tareas reales, entonces una forma de resolver esto es usar colas de mensajes POSIX . Se nombran y funcionan entre procesos. He aquí un breve ejemplo. Tenga en cuenta que solo el primer subproceso de trabajo inicializa la cola de mensajes, los demás usan los atributos del existente. Además, (podría) permanecer persistente hasta que se elimine explícitamente usando mq_unlink , que omití aquí por simplicidad.
Receptor con subprocesos de trabajo :
// Link with -lrt -pthread #include <fcntl.h> #include <mqueue.h> #include <pthread.h> #include <stdio.h> #include <unistd.h> void *receiver_thread(void *param) { struct mq_attr mq_attrs = { 0, 10, 254, 0 }; mqd_t mq = mq_open("/myqueue", O_RDONLY | O_CREAT, 00644, &mq_attrs); if(mq < 0) { perror("mq_open"); return NULL; } char msg_buf[255]; unsigned prio; while(1) { ssize_t msg_len = mq_receive(mq, msg_buf, sizeof(msg_buf), &prio); if(msg_len < 0) { perror("mq_receive"); break; } msg_buf[msg_len] = 0; printf("[%lu] Received: %s\n", pthread_self(), msg_buf); sleep(2); } } int main() { pthread_t workers[5]; for(int i=0; i<5; i++) { pthread_create(&workers[i], NULL, &receiver_thread, NULL); } getchar(); }Remitente :
#include <fcntl.h> #include <stdio.h> #include <mqueue.h> #include <unistd.h> int main() { mqd_t mq = mq_open("/myqueue", O_WRONLY); if(mq < 0) { perror("mq_open"); } char msg_buf[255]; unsigned prio; for(int i=0; i<255; i++) { int msg_len = sprintf(msg_buf, "Message #%d", i); mq_send(mq, msg_buf, msg_len, 0); sleep(1); } }