# Porting Java's synchronized() block to C++

I tried to create a class for porting Java's synchronized keyword to C++ using below code using *nix pthread's library.

In general my test cases seem to work, but since this is a very critical topic I would like to have someone else have a look on it in case I missed something which might invalidate my test cases.

The basic idea is that I created a synchronized(){} block using a #define with help of an if() statement (at the very end of the source).

The synchronized(variableORpointer){} block uses a variable as a reference OR a pointer and using template functions it finally creates/deletes a mutex and condition variable dynamically for the given address using a pointer to referent OR given pointer.

It also supports Java's notify/notifyAll/wait functions using Synchronized::notify(variable), Synchronized::notifyAll(variable) and Synchronized::wait(variable, timeoutInMs, nanos) functions.

A null pointer or not holding the lock on calling wait() causes an std::runtime_error to be thrown.

The most current code is hosted on GitHub including a test example.

#ifndef __SYNCHRONIZED_HPP__
#define __SYNCHRONIZED_HPP__

#include <map>
#include <iostream>
#include <stdexcept>
#include <typeinfo>
#include <sys/time.h>
#include <errno.h>

class Synchronized{
protected:
typedef struct metaMutex{

int counter;
} metaMutex;

return lock;
}
std::map<const void*, metaMutex*>& getMutexMap(){
static std::map<const void*, metaMutex*> mmap;
return mmap;
}

const void *accessPtr;
metaMutex *metaPtr;
int dereference;

template<typename T>
T * getAccessPtr(T & obj) { return &obj; } //turn reference into pointer!
template<typename T>
T * getAccessPtr(T * obj) { return obj; } //obj is already pointer, return it!

public:
template<typename T>
Synchronized(const T &ptr, bool lockit=true) : accessPtr(getAccessPtr(ptr)){
//std::cout << "type: " << typeid(ptr).name() << std::endl;

if(this->accessPtr==NULL){
throw std::runtime_error(std::string("Synchronizing on NULL pointer is not valid, referenced type is: ")+typeid(ptr).name());
}

std::map<const void*, metaMutex*>& mmap = this->getMutexMap();
std::map<const void*, metaMutex*>::iterator it = mmap.find(this->accessPtr);
if(it != mmap.end()){
this->metaPtr = it->second;
this->metaPtr->counter++;
}
else{
this->metaPtr = new metaMutex();
this->metaPtr->counter = 1;
mmap.insert(std::make_pair(this->accessPtr, this->metaPtr));
}

if(lockit){
}
}

operator int() { return 1; }
return this->accessPtr;
}

~Synchronized(){

metaPtr->counter--;
if(metaPtr->counter<=0){
this->getMutexMap().erase(this->accessPtr);
delete metaPtr;
}
}

void wait(unsigned long milliseconds=0, unsigned int nanos=0){
throw std::runtime_error(std::string("trying to wait is only allowed in the same thread holding the mutex"));
}

int rval = 0;
if(milliseconds == 0 && nanos == 0){
}
else{
struct timespec timeUntilToWait;
struct timeval now;
int rt;

gettimeofday(&now,NULL);

timeUntilToWait.tv_sec = now.tv_sec;
long seconds = 0;
if(milliseconds >= 1000){
seconds = (milliseconds/1000);
milliseconds -= seconds*1000;
}
timeUntilToWait.tv_sec += seconds;
timeUntilToWait.tv_nsec = (now.tv_usec+1000UL*milliseconds)*1000UL + nanos;
}
switch(rval){
case 0:
break;
case EINVAL: throw std::runtime_error("invalid time or condition or mutex given");
case EPERM: throw std::runtime_error("trying to wait is only allowed in the same thread holding the mutex");
}
}
void notify(){
std::runtime_error("non initialized condition variable");
}
}
void notifyAll(){
std::runtime_error("non initialized condition variable");
}
}

template<typename T>
static void wait(const T &ptr, unsigned long milliseconds=0, unsigned int nanos=0){
Synchronized syncToken(ptr, false);
syncToken.wait(milliseconds, nanos);
}
template<typename T>
static void notify(const T &ptr){
Synchronized syncToken(ptr, false);
syncToken.notify();
}
template<typename T>
static void notifyAll(const T &ptr){
Synchronized syncToken(ptr, false);
syncToken.notifyAll();
}
};

/* from http://stackoverflow.com/questions/1597007/creating-c-macro-with-and-line-token-concatenation-with-positioning-macr */
#define synchronizedTokenPaste(x,y) x ## y
#define synchronizedTokenPaste2(x,y) synchronizedTokenPaste(x,y)
#define synchronized(ptr) if(Synchronized synchronizedTokenPaste2(sync_, __LINE__) = Synchronized(ptr))
#endif

• Is C++11 an option? – Barry Sep 26 '15 at 16:19
• Careful with names starting with a double underscore. You see a lot of those in the standard library precisely because they are reserved for library use: stackoverflow.com/q/228783/1198654 – glampert Sep 26 '15 at 18:09
• @Barry in general yes, cause i implemented it this way out of interest and with the best of my (non existing C++11) knowledge - additionally it would be very kind if you might have a look at my code too regarding possible synchronization flaws in my code since i'm not that much expirienced with condition variables and i'm also a bit unsure about the last lines in the constructor on unlocking/locking might cause a race condition? – John Doe Sep 27 '15 at 10:31
• @glampert you mean the define symbol? Thanks for your hint - such detailed standard naming conventions are pretty new to me – John Doe Sep 27 '15 at 10:33

C++ is not Java

I cannot stress that enough. You're trying to shoehorn a Java thing into C++, and we end up with macros. Macros are an awful solution to just about every problem and unless you have a compelling reason to use one, don't. This is not a compelling reason. For instance, we could just write:

synchronized(container, [&]{
// stuff
});


It's a couple more characters than your solution, while also not having to be a macro. I think that's worth it.

Also, let's use some C++11 features, which are way easier to use with the introductions of <mutex> and <condition_variable> and <unordered_map>.

synchronized(), as a function

If you wrote it as a function, it would look like:

template <typename T, typename F>
void synchronized(T const& obj, F&& func)
{
std::lock_guard<std::mutex> outer(SynchroObjects::synchro_mutex);
std::lock_guard<std::mutex> inner(_synchro_objects[&obj].mutex);
std::forward<F>(func)();
}


That's it. Sure, I have to show you what _synchro_objects is. But this is the power of C++11. We use RAII for locking (no lock() or unlock()), keep the mutex in a map, and don't need macros. That is super cool.

We just need some other utilities:

struct SynchroObjects {
static std::mutex synchro_mutex;
std::mutex mutex;
std::condition_variable cv;
};

static std::unordered_map<const void*, SynchroObjects> _synchro_objects;


Other utility functions

Once we approach things from this perspective, all the other functions just sort of fall into place and are all just a couple lines:

template <typename T>
SynchroObjects& getSynchro(T const& container) {
std::lock_guard<std::mutex> lk(SynchroObjects::synchro_mutex);
return _synchro_objects[&container];
}

template <typename T>
void notify(T const& container) {
getSynchro(container).cv.notify_one();
}

template <typename T>
void wait(T const& container) {
// potentially you could add some safety checking to ensure
// that _synchro_objects[&container] exists here, maybe use
// at() in debug mode or something

auto& sync = getSynchro(container);
std::unique_lock<std::mutex> lk(sync.mutex);
sync.cv.wait(lk);
}

// wait(T const&, Predicate);
// wait_for(...);
// wait_until(...);

• Thats a really awesome example of using many new c++11 features i'm not yet much aware of . Thanks for sharing your enthusiasm on c++11. Regarding your code, am i right that there is a flaw in the synchronized function cause of not locking _synchro_objects itself? So this is meant as c++11-focused example code, right? Could you also elaborate a bit on your first paragraph? Cause the java design pattern on hiding mutex's and focusing on the resource for synchronization is pretty valuable. Thats why i think synchronizing via the resource itself would be great in c++ and/or c++11. – John Doe Sep 27 '15 at 10:37
• @JohnDoe Good point, I corrected the flaw. Also, the Java design pattern is valuable but C++ is not Java. In C++, we do C++ things. If you need a specific container synchronized, you should just have a mutex along with that container somewhere - don't add this extra outer layer to it. – Barry Sep 27 '15 at 10:46
• Thanks - I'll try to merge this all in some kind of {Synchronized localVar(resource); } way – John Doe Sep 27 '15 at 10:49
• «Macros are an awful solution to just about every problem»: I dare to vehemently disagree. The only problem with macros is that they have global scope, but then again so do most of the language keywords anyway: you cannot use "const" as the name of a variable, for instance, and that's no different than declaring that synchronized is a new keyword injected in the language by an external library of sorts. The preprocessor is part of the language, after all. – Fabio A. Jun 21 '18 at 8:34