Guett31
Guett31

Reputation: 362

Unexplained dead lock situation when using static mutex in function

The code below is an extreme simplification of the actual code I'm dealing with. This is just for anyone to be able to reproduce the issue I'm facing.

#include <mutex>
#include <thread>

using std::mutex;
using std::thread;

void Do()
{
   static mutex myMutex;
   static int dataToProtect;
   return;
}

class MyClass
{
   public:
      ~MyClass()
      {
         mythread_.join();
      }


      void RunMyThread()
      {
         mythread_ = thread(&Do);
      }

      static MyClass *Instance()
      {
         static MyClass single;
         return &single;
      }

   private:
      MyClass()
      {}

      std::thread mythread_;
};



int main()
{
   MyClass::Instance()->RunMyThread();
   return 0;
}

When complied with gcc on MinGW-w64, the execution gets stuck in:

static mutex myMutex;

It looks like the combination of the thread and the singleton design create this issue, because if I call Do() without using a thread:

  void RunMyThread()
  { 
     // mythread_ = thread(&Do);
     Do();
  }

the program executes to the end. Or, if I get around the singleton design by making the constructor public, and I call RunMyThread() through an instance of MyClass:

int main()
{
   // MyClass::Instance()->RunMyThread();
   MyClass o;
   o.RunMyThread();
   return 0;
}

the program executes to the end as well.

Now, if I compile the original code at the top with gcc on Linux, there is no issue. The program executes to the end.

I can't figure out what behavior in this code is platform dependent. Any idea?

Upvotes: 0

Views: 248

Answers (2)

Guett31
Guett31

Reputation: 362

Considering the previous comments/answers, a simple answer to the question is: Allowing a thread to execute after the main function returns is what causes the undefined behavior. (If code portability is a requirement, this should be avoided.)

Upvotes: 1

Mike Collins
Mike Collins

Reputation: 452

This is most likely caused by the order that things are cleaned up in the Windows runtime. You can test this by adding an explicit call to your class like this:

ShutDown()
{
   mythread_.join();
}

Take the join call out of the destructor. Then in your main function:

int main()
{
   MyClass::Instance()->RunMyThread();
   MyClass::Instance()->ShutDown();
   return 0;
}

Upvotes: 1

Related Questions