jeudi 26 février 2015

Thread.Join not return while called in global var destructor(C11 STL)

Using C++11 STL with VS2013 to implementing a asynchronous print class. Failing to get thread.join() returns with no deadlocking. I am trying to debug and finally find that this issue may related to global/local class variable declaration. Here is the details and I dont know why it happened?



#include <iostream>
#include <string>
#include <chrono>
#include <mutex>
#include <thread>
#include <condition_variable>
#include "tbb/concurrent_queue.h"
using namespace std;

class logger
{
public:
~logger()
{
fin();
}

void init()
{
m_quit = false;
thread printer(bind(&logger::printer, this));
m_thd.swap(printer);
}

void fin()
{
unique_lock<mutex> locker(m_mtx);
if (m_thd.joinable())
{
m_quit = true;
write("fin");
locker.unlock();

m_thd.join();
}
}

void write(const char *msg)
{
m_queue.push(msg);
m_cond.notify_one();
}

void printer()
{
string msgstr;
unique_lock<mutex> locker(m_mtx);
while (1)
{
if (m_queue.try_pop(msgstr))
cout << msgstr << endl;
else if (m_quit)
break;
else
m_cond.wait(locker);
}
}

bool m_quit;
mutex m_mtx;
condition_variable m_cond;
thread m_thd;
tbb::concurrent_queue<string> m_queue;
};


For more convenience I placed thread.join into class's destructor in order to ensure the m_thread can be quit normally. I test the whole class and something wrong occured. m_thd.join() never return when class logger declared as a global var like this:



logger lgg;

void main()
{
lgg.init();
for (int i = 0; i < 100; ++i)
{
char s[8];
sprintf_s(s, 8, "%d", i);
lgg.write(s);
}

//if first call lgg.fin() here, m_thd can be joined normally
//lgg.fin();

system("pause");
//dead&blocked here and I observed that printer() finished successfully
}


If class logger declared as a local variable, it seems everything works well.



void main()
{
logger lgg;
lgg.init();
for (int i = 0; i < 100; ++i)
{
char s[8];
sprintf_s(s, 8, "%d", i);
lgg.write(s);
}

system("pause");
}

Aucun commentaire:

Enregistrer un commentaire