Mutex

You may also want to read the article about std::thread.

One should first consider what the plural of mutex should be. The rather awkward sounding and looking mutexes seems to be the current preference, but that may change: Many of us can remember when data was treated as singular before our Latin lessons kicked in and we remembered that the singular is datum.

std::mutex is the flip side of std::thread. After all, if a few of your threads are going to share most of the process's memory, then they can be neither butting heads nor trampling on each other's work.

Inside the functions that are called in the code shown in the std::thread discussion, std::mutex is used to update the message object that the threads share and need to fill with important information. The following snippet illustrates how it is done, although some simplifications to the code have been made to "increase clarity," as people like to say.

 999 static std::mutex processMessageMutex;
1000 
1001 void updateGlobalMessage(const std::string paramName, const dgiRowSet_t & value)
1002 {
1003   dgiMessage_t & m = *::pm;
1004   std::lock_guard<std::mutex> myLock(processMessageMutex);
1005   m[paramName] = value;
1006 }

As with std::thread, we will take this example line by line and try not to give the explanation by comparing it to some other thread/mutex implementation you may not know.

Line 999 creates the mutex. In the example, it is created statically because it is only accessed within this translation unit, and does not need to be globally available. Mutexes are created ready-to-use, so unlike a Julia Child recipe, we do not need to start three days ahead getting things ready.

std::mutex is a type, although as an abstract type its implementation is up to the environment. In its simplest form, it really does not need any properties except to be able to capable of retaining its state of in-use and available. And it is really important for novices to realize that there is no built in association between the mutex and the datum or operation it controls. In other words, we did not construct the mutex by passing in the datum or the name of the function.

If lines 1000, 1001, and 1002 create a problem for you, this article is probably too advanced for you. :-)

Line 1003 may be a little confusing, and I want to ensure that it does not cause a problem in understanding. The shared message is a heap allocated hodge-podge of data, and the global pointer pm is the method of access to it. However, rather than littering the code with a lot of -> operations that might be error prone, line 1003 is a syntactic simplification. It creates a reference to the thing pointed to by pm.

Line 1004 is the business end of the mutex operations. Another STL creature, the std::lock_guard, is used to create a lock of the mutex in question. As you might suspect coming from the STL, std::lock_guard is a template, and the statement creates a parameterized type of lock_guard object that is suitable for getting exclusive use of a std::mutex.

Line 1005 (and other lines that you might want to execute without crashing into your fellow thread's operations) is the protected statement --- so long as the treaty exists that the only way to modify the *::pm object is through this function.

The lock_guard object gets destroyed here, thereby allowing another thread to proceed. This automatic unlock when the function terminates is what makes this particular sequence of statements so useful.

Now, there are other types of locks in the STL, each one of which is optimized for a particular kind of operation. The std::lock_guard is the simplest of the various means, and perhaps the most useful, which is why it is described here. Additional ones are described in 30.4.2.