In my application in C++ I am using pthreads. I have a main thread that parcels out work to another thread to read from disk and a third thread to write to disk. This allows the main thread to perform in real-time and not get hiccups due to disk io by the read thread keeping ahead of the main threads consumption and the write thread keeping up with the main threads production. In other words, the read thread produces data for processing by the main thread and the write thread consumes data produced by the main thread.
In my application, I have shared resources between the main thread and the read thread and I have another set of shared resources between the main thread and the write thread. During periods when no synchronization between threads is needed, the main thread freely accesses the the shared resources of the read and write threads. Then, when it wishes to supply work to be read or written, it sets up the shared resources to indicate the required work and then releases a condition variable to notify the read or write thread (as appropriate) that it should gather the request from the shared area. It then blocks itself until the requested thread completes its gathering of the request and releases a separate condition variable upon which it waits. In this way, the main thread in its normal state accesses the shared resource and then blocks itself by waiting on the condition during periods when its read or write thread needs access, whereas the read and write threads are opposite in that in their normal state they do not access the shared resource, but only do so during synchronization periods when the main thread has signaled and is waiting for them to complete their access.
Here is some very rough pseudo code (do not worry about exact flow here, this is just a rough idea of the functioning code):
MainThread:
do {
While (no pending requests) {
manipulate shared resources;
}
if (need write && ready for read requests) {
setup write request in shared resources;
Release condition startWrite variable;
Wait on condition endWrite variable;
}
if (need read && ready for read requests) {
setup read request in shared resources;
Release condition startRead variable;
Wait on condition endRead variable;
}
}
ReadThread:
do {
Notify I am ready for read requests;
Wait on condition startRead;
copy request out of shared resources;
update shared resources to account for reads completed;
Release condition EndRead;
Perform Read from disk;
}
WriteThread:
do {
Notify I am ready for write requests;
Wait on condition startWrite;
copy request out of shared resources;
update shared resources to account for writes completed;
Release condition EndWrite;
Perform write to disk;
}
My question is whether this is considered just a normal producer consumer design pattern or whether there is a more specific commonly accepted design pattern that would describe what I have created?
You’re getting some background activity to perform input and output, independently of the mainline processing. Reads can be scheduled ahead of time so the data is already there when needed, and writes can be farmed out to as a background activity so the mainline doesn’t have to block on comitting data to storage.
This “design pattern” has a name, being known as “asynchronous IO”.