我正在尝试在我的 C ++ 应用中实现无阻塞串行通信。一个线程负责进行串行通信,我编写了一个ThreadSafeClass
以在串行线程和主线程之间交换数据。这是我的代码的核心:
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
以及串行声明/定义
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(); }
}
问题是,当 serial.cpp 中的串行线程tryDequeue(...)
调用run()
时,它总是看到空的outQueue
。但是,即使在以后的时间, while 循环仍会在 main.cpp 中看到outQueue
具有提供的数据。我发现使用vscode的调试工具。我是C ++的新手,但是有其他语言的经验。我在上面的代码中做错了什么? run()
和main()
看到不同的对象吗?
编译器:g ++ 7.3.0,环境:Linux(Ubuntu 18.04)
编辑:如果我从static
和inQueue
的定义中删除了outQueue
,则两者的链接器都会出现multiple definition
错误。尽管我有适当的包括后卫。
答案 0 :(得分:2)
(在修复了所有非问题之后,我终于发现了实际的问题之后,进行了大量编辑:)
问题是您有两个完全独立的outQueue
实例:main.o
中的一个实例和serial.o
中的一个实例(如果是.obj
您在Windows上)。问题是您在标头中将它们声明为static
。这样会在每个包含该标头的*.cpp
/对象中得到单独的副本。
理想情况下,outQueue
不是全局变量。假设它应该是一个全局变量,则可以这样解决:
serial.hpp
namespace serial
{
// This is a declaration of a global variable. It is harmless
// to include this everywhere.
extern tsqueue::ThreadSafeQueue<std::string> inQueue;
extern tsqueue::ThreadSafeQueue<std::string> outQueue;
}
serial.cpp
namespace serial
{
// This is the actual definition of the variables.
// Without this you get unresolved symbols during link time
// (but no error during compile time). If you have this in
// two *.cpp files you will get multiple definition linker
// errors (but no error at compile time). This must not be
// static because we want all other objects to see this as well.
tsqueue::ThreadSafeQueue<std::string> inQueue;
tsqueue::ThreadSafeQueue<std::string> outQueue;
}
ThreadSafeQueue
本身对我来说还不错。