所以我正在弄乱ConcurrentQueue(找到here)并且我在ConcurrentQueue的破坏期间遇到了Seg Fault(在concurrentqueue.h的第3397行的Seg Faults)。我尝试在多个其他上下文中使用队列但是它在这个上下文中使用时只会导致Seg Fault(下面的代码。)(这让我想知道我的代码是否导致了这个)。
#ifndef MPSCWORKER_MPSCWORKER_HPP
#define MPSCWORKER_MPSCWORKER_HPP
#include <atomic>
#include <condition_variable>
#include <exception>
#include <memory>
#include <thread>
#include "ConcurrentQueue.h"
template <class Type>
class SinkBase;
class SinkNotRegisteredException;
template <class Type, const unsigned int numOfSinks>
class MPSCWorker{
public:
//Funcs
MPSCWorker();
~MPSCWorker(){
Type msg = {};
//Send an empty msg to the reserved channel to say we're done.
send(msg, numOfSinks + 1);
if(workerThread.joinable())
workerThread.join();
for(int i = 0; i <= numOfSinks + 1; i++){
if(sinks[i].get() != nullptr){
sinks[i].get()->onExit();
}
}
}
void start(){
isThreadRunning.store(true);
workerThread = std::thread(run,
std::ref(workQueue),
std::ref(sinks),
std::ref(isThreadRunning),
std::ref(threadCondVar),
std::ref(threadMutex));
}
int addSink(std::unique_ptr<SinkBase<Type>> &&sink, unsigned int sinkID){
if(!isThreadRunning.load()){
if(sinkID <= numOfSinks + 1){
sinks[sinkID] = std::move(sink);
if(!sinks[sinkID].get()->onInit()){
return -3;
}
} else{
return -1;
}
}else{
return -2;
}
return 0;
}
void send(Type msg, unsigned int sinkID){
workQueue.enqueue(InternalType{msg, sinkID});
threadCondVar.notify_one();
}
private:
//Types
struct InternalType{
Type msg;
unsigned int sinkID;
};
//Vars
std::atomic<bool> isThreadRunning;
std::thread workerThread;
std::condition_variable threadCondVar;
std::mutex threadMutex;
//ID = numOfSinks + 1: reserved
std::unique_ptr<SinkBase<Type>> sinks[numOfSinks + 1];
moodycamel::ConcurrentQueue<InternalType> workQueue;
//Funcs
static void run(moodycamel::ConcurrentQueue<InternalType> &workQueue,
std::unique_ptr<SinkBase<Type>> (&sinks)[numOfSinks + 1],
std::atomic<bool> &isThreadRunning,
std::condition_variable &threadCondVar,
std::mutex &threadMutex){
while(isThreadRunning.load()){
InternalType msg = {};
bool isDequeueSuccess = false;
std::unique_lock<std::mutex> lock(threadMutex);
threadCondVar.wait(lock, [&workQueue, &msg, &isDequeueSuccess](){
isDequeueSuccess = workQueue.try_dequeue(msg);
return isDequeueSuccess;
});
if(msg.sinkID == numOfSinks + 1){
isThreadRunning.store(false);
return;
}
if(sinks[msg.sinkID].get() != nullptr){
sinks[msg.sinkID].get()->onProcess(msg.msg);
}else{
throw SinkNotRegisteredException("Sink ID: " + std::to_string(msg.sinkID)
+ " has not been registered. Use addSink"
"to associate this ID with a Sink before"
"starting the worker.");
}
}
}
};
template <class Type, const unsigned int numOfSinks>
MPSCWorker<Type, numOfSinks>::MPSCWorker(){
isThreadRunning.store(false);
for(unsigned int i = 0; i <= numOfSinks +1; i++){
sinks[i] = nullptr;
}
}
class SinkNotRegisteredException : std::exception{
public:
SinkNotRegisteredException(std::string msg){this->msg = msg;}
const char* what(){return msg.c_str();}
std::string whatStr(){return std::string(msg);}
private:
std::string msg;
};
template <class Type>
class SinkBase{
public:
virtual bool onInit() = 0;
virtual void onExit() = 0;
virtual void onProcess(Type data) = 0;
};
#endif //MPSCWORKER_MPSCWORKER_HPP
以上是上述代码的示例用法(我知道代码适用于多线程应用程序,但为简单起见,该示例为单线程)。
#include <iostream>
#include "MPSCWorker.hpp"
template <class Type>
class PrintSink : public SinkBase<Type>{
public:
virtual bool onInit(){return true;}
virtual void onExit(){}
virtual void onProcess(Type data){std::cout << data << std::endl;}
};
int main(){
MPSCWorker<std::string, 1> worker;
std::unique_ptr<PrintSink<std::string>> sink(new PrintSink<std::string>);
if(sink.get() == nullptr){
return -1;
}
worker.addSink(std::move(sink), 0);
worker.start();
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
worker.send("test", 0);
return 0;
}
现在真正的问题是:我的代码是否导致Seg Fault?或者是ConcurrentQueue做错了什么?无论如何,如何解决这个问题?