Home > Articles > Programming > C/C++

  • Print
  • + Share This
Like this article? We recommend

Like this article? We recommend

Class-Level Locks

Class-Level Locks

The example in Listing 1 is very simplistic in nature. In a more realistic scenario, locking semantics are provided at the class level; that is, a mutex is included as a field in a class definition, along with an associated accessor method. Listing 4 illustrates a class called Person.

Listing 4—A class-level mutex.

class Person {
      private:
      std::mutex classMutex;
      string name;
      int age;

      public:
      Person(string name, int age);
      virtual ~Person();
      string getName();
      void setName(string newName);
      int getAge();
      void setAge(int newAge);
};

Notice in Listing 4 that the class Person includes a mutex field called classMutex. As in the previous example, the mutex in Listing 4 is used to protect against simultaneous access to shared objects of class Person. Obviously, if only one thread can modify an instance of class Person, there's no need for the mutex. But if multiple threads of execution can access the same object, we need a locking mechanism, as illustrated in Listing 5.

Listing 5—Implementing a class-level mutex on setters.

Person::Person(string name, int age) {
    this->name = name;
    this->age = age;
}

Person::~Person() {
}

string Person::getName() {
  return this->name;
}

void Person::setName(string newName) {
    std::lock_guard<std::mutex> lk(classMutex);
    this->name = newName;
}

int Person::getAge() {
  return this->age;
}

void Person::setAge(int newAge) {
    std::lock_guard<std::mutex> lk(classMutex);
    this->age = newAge;
}

In Listing 5, notice that I use the lock for all data modifications. There is still a potential problem in Listing 5, though, because any access to the getter functions might potentially result in race conditions. To be rigorous, we really should use the lock for the getters as well as the setters, as in Listing 6.

Listing 6—Implementing a class-level mutex on getters and setters.

Person::Person(string name, int age) {
    this->name = name;
    this->age = age;
}

Person::~Person() {
}

string Person::getName() {
    std::lock_guard<std::mutex> lk(classMutex);
    return this->name;
}

void Person::setName(string newName) {
    std::lock_guard<std::mutex> lk(classMutex);
	this->name = newName;
}

int Person::getAge() {
    std::lock_guard<std::mutex> lk(classMutex);
    return this->age;
}

void Person::setAge(int newAge) {
    std::lock_guard<std::mutex> lk(classMutex);
    this->age = newAge;
}

In Listing 6, we should now have no race conditions. Listing 7 illustrates a complete run of the new program.

Listing 7—A new program run.

Hello World - sharedDataItem: 100
Starting threads
Thread ID 1 3075812208
Thread ID 2 3067419504
Thread ID 3 3059026800
Hello Concurrent World 2 - attempting to lock mutex!
Hello Concurrent World 2 - successfully locked mutex!
Hello Concurrent World 3 - attempting to lock mutex!
Hello Concurrent World 1 - attempting to lock mutex!
Hello Concurrent World 2 - just about to unlock mutex!
Hello Concurrent World 3 - successfully locked mutex!
Hello Concurrent World 3 - just about to unlock mutex!
Hello Concurrent World 1 - successfully locked mutex!
Hello Concurrent World 1 - just about to unlock mutex!
After threads - sharedDataItem: 106
Time to create somebody!
Person1 name: Johnny Doe
Person1 age: 100
Person1 modified age: 101
  • + Share This
  • 🔖 Save To Your Account