如果在结构内部使用condition_variable则无法使用

时间:2018-07-29 13:18:17

标签: c++ condition-variable

如果在结构内使用

condition_variable则无法使用。如果我将其作为全局变量,则一切正常。但是我每个包都需要一个condition_variable,因为我不知道何时会收到答案,我需要为每个包等待它。我在做什么错了?

这是控制台输出:

Wait: 416
StopWait: 423

从中我可以看到我在锁定数据后接收到数据并解锁了线程。

结构

struct Waiting {
    bool IsWaiting = false;
    mutable std::condition_variable cv;
    mutable std::mutex m;

    clock_t localCLock = 0;

    void Wait() const {
        const double ms = Utils::MillisecondsSpent(localCLock);
        std::cout << "Wait: " << ms << std::endl;

        std::unique_lock<std::mutex> lock(m);
        cv.wait(lock, [this] { return IsWaiting; });
    }

    void StopWait() {
        const double ms = Utils::MillisecondsSpent(localCLock);
        std::cout << "StopWait: " << ms << std::endl;

        std::unique_lock<std::mutex> lock(m);
        IsWaiting = true;
        cv.notify_all();
    }
};

struct Packet
{
    Packet() : id(0), waiting(new Waiting) {}

    int id;
    Waiting* waiting;
};

class Map
{
    static Map* instance;

    Map();
    ~Map();

    Map(const Map&) = delete;

public:
    static Map* Instance() {
        if (!instance) instance = new Map;
        return instance;
    }
    std::map<int, Packet> packets;
};

线程

//Send Thread - called first
while(true){
    Packet packet;
    packet.id = 1;

    //some send packet logic here
    ...
    ///

    Map::Instance()->packets.insert(std::pair<int, Packet>(p.id, p));
    Map::Instance()->packets[id].waiting->Wait(); // thread now locked and never unlocks

    const Packet received = Map::Instance()->packets[id];
    Map::Instance()->packets.erase(id);
}

//Receive Thread - called second
while(true){
    //some receive packet logic here
    ...
    ///
    const Packet packet = ... // receive a packet data;

    Map::Instance()->packets[packet.id] = packet;
    Map::Instance()->packets[packet.id].answered = true;
    Map::Instance()->packets[packet.id].waiting->StopWait(); // i unlock Send Thread, but it won't work
}

1 个答案:

答案 0 :(得分:1)

除了同步问题和内存泄漏外,每次分配Packet时,都是按值复制它,并分配了一个新的Waiting。内存中有许多悬空的悬空Waiting对象,并且没有理由在一个对象上调用StopWait会在另一个对象上触发condition_variable

查看我添加的代码注释。

while(true){
    // *** PACKET A ***
    Packet packet; 
    packet.id = 1;

    //*** PACKET B ***
    Map::Instance()->packets.insert(std::pair<int, Packet>(p.id, p));
    Map::Instance()->packets[id].waiting->Wait();
}

while(true){
    // *** PACKET C ***
    const Packet packet = ... 

    //You are overwriting PACKET B with a copy of PACKET C which is PACKET D.
    //Don't you mean to find a packet which has the same id as the received packet instead of overwriting it?
    Map::Instance()->packets[packet.id] = packet;  
    Map::Instance()->packets[packet.id].answered = true;

    // There's no reason calling StopWait on PACKET D's Waiting object will release PACKET B.
    Map::Instance()->packets[packet.id].waiting->StopWait(); 
}