How to do asynchronous inter thread communication on platform with pthreads - multithreading

For example on windows there is MsgWaitForMultipleObjects that lets you asynchronously wait for windows messages, socket events, asynchronous io (IOCompletionRoutine), AND mutex handles.
On Unix you have select/poll that gives you everything except possibility to break out when some pthread_mutex is unlocked.
The story:
I have application that has main thread that does something with multiple sockets, pipes or files. Now from time to time there is a side job (a db transaction) that might take a longer time and if done synchronously in main thread would disrupt normal servicing of sockets. So I want to do the db operation in separate thread. That thread would wait on some mutex when idle until main thread decides to give it some job and unlocks the mutex so db thread can grab it.
The problem is how the db thread can notify back the main thread that it has finished the job. Main thread has to process sockets, so it cannot afford sleeping in pthread_mutex_lock. Doing periodic pthread_mutex_trylock is the last I would want to do. Currently I consider using a pipe, but is this the better way?

Using a pipe is a good idea here. Make sure that no other process has the write end of the pipe open, and then select() or poll() in the main thread the read end for reading. Once your worker thread is done with the work, close() the write end. The select() in the main thread wakes up immediately.
I don't think waiting on a mutex and something else would be possible, because on Linux, mutexes are implemented with the futex(2) system call, which doesn't support file descriptors.

I don't know how well it applies to your specific problem, but posix has message queues.

Related

How can I block a single thread for 3 different events (semaphore, pthread condition, and blocking socket recv)?

I have a multi-threaded system in which a main thread has to wait in blocking state for one of the following 4 events to happen:
inter-process semaphore (sem_wait())
pthread condition (pthread_cond_wait())
recv() from socket
timeout expiring
Ideally I'd like a mechanism to unblock the main thread when any of the above occurs, something like a ppoll() with suitable timeout parameter. Non-blocking and polling is out of the picture due to the impact on the CPU usage, while having separate threads blocking on different events is not ideal due to the increased latency (one thread unblocking from one of the events should eventually wake up the main one).
The code will be almost exclusively compiled under Linux with gcc toolchain, if that helps, but some portability would be good, if at all possible.
Thanks in advance for any suggestion
The mechanisms for waiting on multiple types of objects on Unix-like systems are not that great. In general, the idea is to, wherever possible, use file descriptors for IPC rather than multiple different IPC mechanisms.
From your comment, it sounds like you can edit or change the condition variable, but not the code that signals the semaphore. So what I'd recommend is something like the following.
Change the condition variable to either a pipe (for more portability) or an eventfd(2) object (Linux-specific). The notifying thread writes to the pipe whenever it wants to signal the main thread. This will allow you to select(2) or poll(2) or whatever in the main thread on both that pipe and the socket.
Because you're stuck with the semaphore, I think the best option would be to create another thread, whose sole purpose is to wait for the semaphore using sem_wait(), and then write to another pipe or eventfd(2) object when it is notified by whatever process is doing sem_post(). In the main thread, just add this other file descriptor to your select(2) set.
So you'll have three descriptors: one for the socket, one taking the place of the condition variable, and one which is written to when the semaphore is incremented. You can then wait on all three using your favorite I/O multiplexing method, and include directly whatever timeout you'd like.

How does Blocking I/O operation works in a multithreaded C++ application?

I have a very specific question.
How does blocking I/O operation e.g. recvfrom() call work in a
multithreaded application?
How does the OS schedule a thread that has blocking syscalls?
Would the OS schedule the thread when the blocking system call is
executed (e.g. similar to busy wait?) or would the OS only
schedule the thread once the syscall has returned?
Would that cause an interrupt to the executing the thread (If that is the
case would it worthwhile to code the critical sections of the
other threads within a mutex or some sort of atomic operations?)
How does blocking I/O operation e.g. recvfrom() call work in a
multithreaded application?
The thread is blocked, the others continue to be scheduled. That is one of the main advantages of developing multithreaded applications, even on single core machines.
How does the OS schedule a thread that has blocking syscalls?
Not, until the syscall returns.
Would the OS schedule the thread when the blocking system call is executed (e.g. similar to busy wait?) or would the OS only schedule the thread once the syscall has returned?
The first, what should the thread do while it's in the syscall?
Generally, also the latter would be possible, but it would be a very strange implementation, to say the least, of scheduling. In fact, assume you're the scheduler, so you're currently in kernel space. Execution of the thread is currently not in user space, as it waits for the syscall to return. So where would the thread "continue" to execute?
Would that cause an interrupt to the executing the thread (If that is the case would it worthwhile to code the critical sections of the other threads within a mutex or some sort of atomic operations?)
Well, that is what a blocking call does: halt the execution till the blocking condition has passed.

Can I rely on Linux close() not blocking for file I/O?

I am using Linux aio (io_submit() / io_getevents()) for file I/O. Since some operations do not have aio equilvalents (open(), fsync(), fallocate()), I use a worker thread that may block without impacting the main thread. My question is, should I add close() to this list?
All files are opened with O_DIRECT on XFS, but I am interested in both the general answer to the question, and on the specific answer with regard to my choice of filesystem and open mode.
Note that using a worker thread for close() is not trivial since close() is often called in cleanup paths, which aren't good places to launch a worker thread request and wait for it. So I'm hoping that close() is non-blocking in this scenario.
For this question, "blocking" means waiting on an I/O operation, or on some lock that may only be released when an I/O operation completes, but excluding page fault servicing.
close() may block on some filesystems. When possible, code should be written as portably as is practical. As such, you should definitely add close() to the list of calls that are called only from your blocking worker thread.
However, you mention that you often have to call close() in cleanup paths. If these are cleanup paths that execute at the termination of your application, it may not make as much of a difference even if close() does block if you call it directly.
Alternatively, what you could do would be to have a queue that is fed to a pool of workers. In glibc AIO, this is what is done for many calls. When you initialize AIO with aio_init(), glibc sets up a queue and a pool of worker threads. Every time an AIO call is made, glibc simply adds the relevant task and data to the queue. In the background, the worker threads wait on the queue and execute blocking calls and code and then perform any relevant actions.
If you really do have the need for a non-blocking close() (and other) calls, it may be to your advantage to simply setup a task queue and a thread pool and simply submit specific calls to the queue and have the thread pool execute calls as they come in.

Mechanism of join() in multithreading

I was studying about multi-threading and came across join().
As I understand right, using join() on the thread makes process wait until 'joined' thread terminates. For example, calling t1.join() in main will make main wait until the job in thread t1 is finished and t1 terminates.
I'm just curious that how the function join() make this possible - how does it make current thread 'blocked' inside the function? Does join() force execution of joined thread first so any other thread should wait until that thread terminates? Or, is there some way to communicate between two threads(the thread who called join() and the thread who is joined)?
I will be waiting for the answer. Thanks a lot!
To be able to join you need to be able to wait on some event. Then join looks like this:
function join(t : Thread)
// do this atomically
if already done
return
wait on termination event of t
end
Waiting can be done in one of two ways:
Looping and periodically checking if the event has happened (busy wait)
Letting the system reclaim the resources of the thread and be woken up on a system event, in that case waking the thread is managed by the scheduler of the OS
It's rather language specific.
Once you create a thread, it starts running.
A join operation is when your main process stops and waits for the thread to exit and capture a return code. It will block until your thread completes - that's rather the point, as it allows for a synchronization to occur - everything in your program is at a 'known state'.
Related is the detach operation, which is effectively saying 'I don't care any more'.

Mutex lock: what does "blocking" mean?

I've been reading up on multithreading and shared resources access and one of the many (for me) new concepts is the mutex lock. What I can't seem to find out is what is actually happening to the thread that finds a "critical section" is locked. It says in many places that the thread gets "blocked", but what does that mean? Is it suspended, and will it resume when the lock is lifted? Or will it try again in the next iteration of the "run loop"?
The reason I ask, is because I want to have system supplied events (mouse, keyboard, etc.), which (apparantly) are delivered on the main thread, to be handled in a very specific part in the run loop of my secondary thread. So whatever event is delivered, I queue in my own datastructure. Obviously, the datastructure needs a mutex lock because it's being modified by both threads. The missing puzzle-piece is: what happens when an event gets delivered in a function on the main thread, I want to queue it, but the queue is locked? Will the main thread be suspended, or will it just jump over the locked section and go out of scope (losing the event)?
Blocked means execution gets stuck there; generally, the thread is put to sleep by the system and yields the processor to another thread. When a thread is blocked trying to acquire a mutex, execution resumes when the mutex is released, though the thread might block again if another thread grabs the mutex before it can.
There is generally a try-lock operation that grab the mutex if possible, and if not, will return an error. But you are eventually going to have to move the current event into that queue. Also, if you delay moving the events to the thread where they are handled, the application will become unresponsive regardless.
A queue is actually one case where you can get away with not using a mutex. For example, Mac OS X (and possibly also iOS) provides the OSAtomicEnqueue() and OSAtomicDequeue() functions (see man atomic or <libkern/OSAtomic.h>) that exploit processor-specific atomic operations to avoid using a lock.
But, why not just process the events on the main thread as part of the main run loop?
The simplest way to think of it is that the blocked thread is put in a wait ("sleeping") state until the mutex is released by the thread holding it. At that point the operating system will "wake up" one of the threads waiting on the mutex and let it acquire it and continue. It's as if the OS simply puts the blocked thread on a shelf until it has the thing it needs to continue. Until the OS takes the thread off the shelf, it's not doing anything. The exact implementation -- which thread gets to go next, whether they all get woken up or they're queued -- will depend on your OS and what language/framework you are using.
Too late to answer but I may facilitate the understanding. I am talking more from implementation perspective rather than theoretical texts.
The word "blocking" is kind of technical homonym. People may use it for sleeping or mere waiting. The term has to be understood in context of usage.
Blocking means Waiting - Assume on an SMP system a thread B wants to acquire a spinlock held by some other thread A. One of the mechanisms is to disable preemption and keep spinning on the processor unless B gets it. Another mechanism probably, an efficient one, is to allow other threads to use processor, in case B does not gets it in easy attempts. Therefore we schedule out thread B (as preemption is enabled) and give processor to some other thread C. In this case thread B just waits in the scheduler's queue and comes back with its turn. Understand that B is not sleeping just waiting rather passively instead of busy-wait and burning processor cycles. On BSD and Solaris systems there are data-structures like turnstiles to implement this situation.
Blocking means Sleeping - If the thread B had instead made system call like read() waiting data from network socket, it cannot proceed until it gets it. Therefore, some texts casually use term blocking as "... blocked for I/O" or "... in blocking system call". Actually, thread B is rather sleeping. There are specific data-structures known as sleep queues - much like luxury waiting rooms on air-ports :-). The thread will be woken up when OS detects availability of data, much like an attendant of the waiting room.
Blocking means just that. It is blocked. It will not proceed until able. You don't say which language you're using, but most languages/libraries have lock objects where you can "attempt" to take the lock and then carry on and do something different depending on whether you succeeded or not.
But in, for example, Java synchronized blocks, your thread will stall until it is able to acquire the monitor (mutex, lock). The java.util.concurrent.locks.Lock interface describes lock objects which have more flexibility in terms of lock acquisition.

Resources