SyncC++

System Monitor for Concurrent Access Control in C++


Concurrent access control is an old problem and has been solved many times in various languages and systems. Monitor is a simple and efficient solution that automatically wraps a critical section in an acquire-lock-or-wait and release-lock pair. Many languages provide the implementation of monitor, such as Java's synchronized, Modula-3's LOCK, Mesa's MONITOR, etc. Unfortunately, the Standard C++ has no such simple and efficient facility since it is silent on the subject of threads.

In " Concurrent Access Control & C++" (C/C++ Users Journal, 22(1):32 - 37, 2004), we demonstrate that the powerful Standard C++ allows us to implement the monitor facility efficiently in only 50 simple lines. Our approach also does not require any extensions to Standard C++.

Here is the source code, in which we implement a macro synchronized for concurrent access control. The usage is the same as the one of Java. For example,

  mutex lock;
  synchronized( lock )
  {
    // do something
  }
where mutex is a class that should provide the methods lock() and unlock().

We also implement two macros syncread and syncwrite for producer and consumer problem. For instance,

  rwlock lock;
  void producer( buffer b )
  {
    object a = make();
    syncwrite( lock )
    {
      b.put( a );
    }
  }

  void consumer( buffer b )
  {
    object a;
    syncread( lock )
    {
      a = b.get();
    }
  }
where rwlock is a read-write lock class that provide the methods rlock(), wlock(), and unlock(). Note that our mutex and rwlock classes are very very plain wrapper of pthread functions for demonstration and should not be used in real applications.

Based on the same idea, we can also solve another important problem: ACID transactions. In the context of database transactions, ACID is a short for "Atomic, Consistent, Isolation, and Durable". Transactions provide a simple model of success or failure. A transaction either commits (that is, all its actions happen) or aborts (all its actions are undone). This all-or-nothing quality makes for a simple programming model. For ACID transaction, the macro transaction is provided. The following is an example.

  #include <iostream>
  #include "sync.h"

  class database
  {
  public:

    database() { }

    ~database() { }

    void database::start( void )
      { std::cout << "start" << std::endl; }

    void database::commit( void )
      { std::cout << "commit" << std::endl; }

    void database::rollback( void )
      { std::cout << "rollback" << std::endl; }

  private:

    // prevent copying
    database(const database&);

    database& operator = (const database&);
  };

  int main()
  {
    int i = 0, j = 0;
    database dbs;

    transaction( dbs )
    {
      i++;
      j++;
    }

    transaction( dbs )
    {
      i++;
      if ( i == 2 ) break;
      j++;
    }

    try
    {
      transaction( dbs )
      {
        i++;
        if ( i == 3 ) throw 1;
        j++;
      }
    }
    catch( ... )
    {
    }

    return 0;
  }

Please send comments and questions to Haifeng Li

Total visits: Web Counter