MACE  1.0.0
 All Classes Namespaces Files Functions Variables Enumerations Defines
Public Member Functions
mace::cmt::mutex Class Reference

mutex More...

#include <mutex.hpp>

List of all members.

Public Member Functions

bool try_lock ()
bool timed_lock (const boost::system_time &abs_time)
void lock ()
void unlock ()
template<typename DurationType >
bool timed_lock (const DurationType &rel_time)

Detailed Description

This mutex has an advantage over boost::mutex in that it does not involve any system calls, even in contention.

Uncontensted access is a simple compare and swap, no delay.

Contested access by different fibers in the same thread simply yields the thread until the lock is available. Actual delay is subject to the cooperative nature of other tasks in the fiber's thread.

Contested access by different threads requires a spin lock while the task is enqueued. Because the enqueue action is well-defined and 'short-lived' time spent 'spinning' should be minimal.

Cooperatively multi-tasked code must still worry about reentrancy. Suppose you have a thread sending a message across a socket, the socket members are thread safe, but the write_message() operation is not rentrant because the context could yield while waiting for a partial write to complete.

If while it has yielded another task in the same thread attempts to write a second message then you will get garbage out as both fibers take turns writing parts of their messages out of the socket.

Example problem:

    async(write_message);
    async(write_message);
    void write_message() {
      sock->write(part1); // may yield
      sock->write(part2); // may yield
      sock->write(part3); // may yield
    }

The output could look something like:

    part1
    part2
    part1
    part3
    part2
    part3

What you want to happen is this:

    void write_message() {
      boost::unique_lock<cmt::mutex> lock(sock->write_lock);
      sock->write(part1); // may yield
      sock->write(part2); // may yield
      sock->write(part3); // may yield
    }

Now if while writing the first message, someone attempts to write a second message second write will 'queue' behind the first by 'blocking' on the mutex.

As a result we now have to extend the normal discussion on thread-safe vs reentrant.

In the example above, before we added the mutex the code was thread-unsafe After we added the mutex the code became coop-thread-safe, and potentially prempt-thread-safe

To be preempt-thread-safe any operations must be atomic or protected by a lock because the OS could switch you out between any two instructions.

To be coop-thread-safe all operations are 'atomic' unless they span a 'yield'. If they span a yield (such as writing parts of a message), then a mutex is required.

Definition at line 90 of file mutex.hpp.


The documentation for this class was generated from the following file: