I am sending the same answer in another message: I want to wait for both the file descriptor and the mutex, what is the recommended way to do this?
==================================================== ========
This is a very common problem, especially when you are developing a network server program. The main view of the main server-side Linux program will look like this:
epoll_add(serv_sock); while(1){ ret = epoll_wait(); foreach(ret as fd){ req = fd.read(); resp = proc(req); fd.send(resp); } }
This is a single-threaded (main thread) epoll based server. The problem is that it is single-threaded, not multi-threaded. This requires proc () to never block or run for a considerable amount of time (e.g. 10 ms for normal cases).
If proc () will work for a long time, WE NEED A LOT OF THREADS and execute proc () in a separate thread (worker thread).
We can send the task to the workflow without blocking the main thread using the message queue based on the mutex, which is fast enough.
Then we need a way to get the result of the task from the workflow. How? If we simply check the message queue directly, before or after epoll_wait (), however, the check action will be performed after epoll_wait () is completed, and epoll_wait () is usually blocked for 10 microseconds (normal cases) if all file descriptors are inactive.
For a server, 10 ms is long enough! Can we signal epoll_wait () for immediate completion when the result of the task is generated?
Yes! I will describe how this is done in one of my open source projects.
Create a tube for all workflows, and epoll waits on this channel as well. As soon as the result of the task is generated, the worker thread writes one byte to the tube, then epoll_wait () will end almost at the same time! - The Linux line has a delay of 5 to 20 seconds.
In my SSDB project (a Redis compatible compatible NoSQL database on disk) I create a SelectableQueue to send messages between the main thread and the worker threads. Like its name, SelectableQueue has a file descriptor that epoll can wait for.
SelectableQueue: https://github.com/ideawu/ssdb/blob/master/src/util/thread.h#L94
Usage in main stream:
epoll_add(serv_sock); epoll_add(queue->fd()); while(1){ ret = epoll_wait(); foreach(ret as fd){ if(fd is worker_thread){ sock, resp = worker->pop_result(); sock.send(resp); } if(fd is client_socket){ req = fd.read(); worker->add_task(fd, req); } } }
Use in workflow:
fd, req = queue->pop_task(); resp = proc(req); queue->add_result(fd, resp);