在销毁ConcurrentQueue期间出现分段错误的原因不明

时间:2015-10-19 18:57:14

标签: c++ multithreading queue lock-free

所以我正在弄乱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做错了什么?无论如何,如何解决这个问题?

0 个答案:

没有答案