Uncoupled communication between two objects which run in separate threads can be achieved through buffers. A buffer is placed between the two communicating objects and can store a single element. There are different types of buffers depending on the context in which they are used but they all share the same interface which supplies two functions: put and get. Three different variations have to be considered:
fully synchronous: put and get both block the calling thread.
A channel is a thread-safe queue which uses semaphores to synchronize access. The underlying queue in this implementation is the C++ std::queue container. It uses two semaphores sem_free_spaces_ to count the free spaces in the queue and avoid overflow and sem_size_ to count the elements in the queue and prevent underflow. In addition a std::mutex is used to synchronize access to the queue.
To enqueue an element to the channel the sem_free_spaces_ semaphore is first decremented which will block on a full queue and then increments the sem_size_ semaphore after adding the element to the queue.
A buffer is used for communication between objects which run in different threads. A buffer wraps some shared memory or a unique pointer thereto. The buffer may be accessed by the two communication partners via reference to the buffer which is initialized via constructor argument.
A buffer is a single block of memory for a message (or unique pointer) and messages are not queued. Check out the channel if you need communication via a message queue.
The very traditional way to implement the observer pattern is by using polymorphism. You have to derive the class which contains your callback function from an observer base class, and you have to overwrite the function notify(). This is done in the first code C++03 sample you see here. Create a ConcreteObserver, derived from Observer, and fill in your personal notify function. The subject stores all ConcreteObservers in a vector. When something changes in the Subject (e.