I'm trying to implement a non-blocking serial communication in my C++ app. A thread is responsible to do serial communication, and I've written a ThreadSafeClass
to exchange data between serial thread and main thread. Here is the core of my code:
main.cpp
#include "serial.hpp"
#include "tsqueue.hpp"
int main(int argc, char *argv[])
{
serial::init();
while (true)
{
fgets(s);
serial::outQueue.enqueue(std::string(s));
}
serial::shutdown();
return 0;
}
tsqueue.hpp
#include <mutex>
#include <queue>
namespace tsqueue
{
template <typename T>
class ThreadSafeQueue
{
private:
mutable std::mutex _mtx;
std::queue<T> _que;
public:
ThreadSafeQueue();
~ThreadSafeQueue();
void enqueue(const T &item);
T tryDequeue(const T &defaultValue, bool &done);
void clear();
bool isEmpty() const;
};
template <typename T>
ThreadSafeQueue<T>::ThreadSafeQueue() {}
template <typename T>
ThreadSafeQueue<T>::~ThreadSafeQueue() { clear(); }
template <typename T>
void tsqueue::ThreadSafeQueue<T>::enqueue(const T &item)
{
std::lock_guard<std::mutex> lock(_mtx);
_que.push(item);
}
template <typename T>
T tsqueue::ThreadSafeQueue<T>::tryDequeue(const T &defaultValue, bool &done)
{
std::lock_guard<std::mutex> lock(_mtx);
if (_que.empty())
{
done = false;
return defaultValue;
}
else
{
T item = _que.front();
_que.pop();
done = true;
return item;
}
}
} // namespace tsqueue
And serial declaration/definition,
serial.hpp
#include <string>
#include "tsqueue.hpp"
namespace serial
{
static tsqueue::ThreadSafeQueue<std::string> inQueue;
static tsqueue::ThreadSafeQueue<std::string> outQueue;
void init();
void shutdown();
}
serial.cpp
#include <string>
#include "serial.hpp"
#include "tsqueue.hpp"
static std::thread _thread;
void run()
{
while (true)
{
std::string str = serial::outQueue.tryDequeue(emptyStr, dequeued);
if (dequeued) { /* Do send 'str' */ }
if (terminationRequested) { break; }
// Some sleep
}
}
void serial::init()
{
serial::inQueue.clear();
serial::outQueue.clear();
_thread = std::thread(run);
}
void serial::shutdown()
{
if (_thread.joinable()) { _thread.join(); }
}
The problem is, when tryDequeue(...)
is called by serial thread's run()
in serial.cpp, it always sees empty outQueue
. However while loop still sees outQueue
in main.cpp with provided data, even at later times. I've find out that using debug tools of vscode. I'm new to C++, but experienced in other languages. What am I doing wrong in above code? Do run()
and main()
see different objects?
Compiler: g++ 7.3.0, Environment: Linux (Ubuntu 18.04)
Edit: If I remove static
from definitions of inQueue
and outQueue
, I get multiple definition
error by linker for both. Although I have appropriate include guards.