Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

homemade scoped lock doesn't lock

Tags:

c++

pthreads

I created the following code for a project where I don't have access to any modern C++ threading libraries like boost. My desire is to have the ability to have the lock automatically release when it leaves scope.

The Shared lock works fine. If a thread acquires it, nothing else can acquire it until the first thread releases it. The Scoped one does not work though.

Here's some output showing what I mean. I gave each thread a distinct name, had them instantiate the Scoped lock with the same Shared lock, print 'acquired', sleep for five seconds, print 'released', then leave scope. Instead of getting the acquire/release pairs I'd expect, I get four 'acquired's in quick succession, a five second gap, then the 'released's. I even changed the lock in Scoped to a pointer, and printed the address before acquiring it, just to make sure I wasn't crazy. It looks like it's the same Shared object, but the lock isn't preventing multiple accesses.

Lock '140734928395200'.
acquired: !!!!!
Lock '140734928395200'.
acquired: -------
Lock '140734928395200'.
acquired: ***************
Lock '140734928395200'.
acquired: ##
released: !!!!!
released: -------
released: ***************
released: ##

Here's the source code for Lock.h:

#include <pthread.h>
namespace Lock
{
  class Shared
  {
  public:
    Shared()
    {
      ::pthread_mutex_init(&(this->mutex), nullptr);
    }
    ~Shared()
    {
    }
    void acquire()
    {
      ::pthread_mutex_lock(&(this->mutex));
    }
    void release()
    {
      ::pthread_mutex_unlock(&(this->mutex));
    }
  private:
    pthread_mutex_t mutex;
  };
  class Scoped
  {
  public:
    Scoped(Lock::Shared& lock) : lock(lock)
    {
      this->lock.acquire();
    }
    virtual ~Scoped()
    {
      this->lock.release();
    }
  private:
    Lock::Shared& lock;
  };
};

Here's my main.cc file for testing. I'm building with:

g++ -std=c++11 -o try -pthread main.cc && ./try

with g++4.7 on an up to date Ubuntu system.

#include <pthread.h>
#include <iostream>
#include "Lock.h"
#include <unistd.h>
struct data
{
  data(std::string name, Lock::Shared& lock) : name(name), lock(lock) { ; }
  std::string name;
  Lock::Shared& lock;
};
void* doStuff(void* v)
{
  data* d = (data*)v;
  for (int i = 0; i < 5; i++)
  {
    Lock::Scoped(d->lock);
    //d->lock->acquire();
    std::cout << "acquired: " << d->name << std::endl;
    ::sleep(5);
    std::cout << "released: " << d->name << std::endl;
    //d->lock->release();
    ::sleep(1);
  }
}
int main(int argc, char* argv[])
{
  pthread_t fred;
  pthread_t barney;
  pthread_t wilma;
  pthread_t betty;
  Lock::Shared lock;
  data f("##", lock);
  data b("***************", lock);
  data w("-------", lock);
  data e("!!!!!", lock);
  ::pthread_create(&fred, nullptr, doStuff, (void*)&f);
  ::pthread_create(&barney, nullptr, doStuff, (void*)&b);
  ::pthread_create(&wilma, nullptr, doStuff, (void*)&w);
  ::pthread_create(&betty, nullptr, doStuff, (void*)&e);
  ::pthread_join(fred, nullptr);
  ::pthread_join(barney, nullptr);
  ::pthread_join(wilma, nullptr);
  ::pthread_join(betty, nullptr);
  return 0;
}
like image 734
kwiqsilver Avatar asked Dec 04 '22 12:12

kwiqsilver


2 Answers

The problem is:

for (int i = 0; i < 5; i++)
{
    Lock::Scoped(d->lock);

which creates a temporaray Lock::Scoped that is constructed and destructed immediately, thus it does not have the intended synchronization effect. Change to:

for (int i = 0; i < 5; i++)
{
    Lock::Scoped lk(d->lock);
like image 139
hmjd Avatar answered Dec 29 '22 20:12

hmjd


The problem is here:

Lock::Scoped(d->lock);

This creates an unnamed temporary that goes out of scope right away.

To fix, give it a name:

Lock::Scoped lck(d->lock);
like image 33
NPE Avatar answered Dec 29 '22 20:12

NPE