std :: condition_variable ::等待不在RaspberryPi上释放锁定

时间:2017-09-20 07:27:22

标签: c++ multithreading raspberry-pi g++ condition-variable

我在Ubuntu上为RaspberryPi(3)编译了一个项目,其中包含来自git://github.com/raspberrypi/tools.git的工具。我想使用与condition_variable的线程同步,但wait_for似乎不会释放提供给它的mutex锁,如文档中所述。以下是在RaspberryPi上重现问题的简化代码(有过多的日志记录以更好地显示问题):

int main(int argc, const char* args[])
{
    std::condition_variable cv;
    std::mutex m;
    bool ok = false;

    std::cout << "locking in main" << std::endl;
    std::unique_lock<std::mutex> lock(m);
    std::cout << "locked in main" << std::endl;

    std::cout << "starting thread" << std::endl;
    std::thread t([&cv, &m, &ok]() {
        std::cout << "locking in thread" << std::endl;
        std::unique_lock<std::mutex> lock(m);
        std::cout << "locked in thread" << std::endl;
        ok = true;

        std::cout << "unlocking in thread" << std::endl;
        lock.unlock();
        std::cout << "signalling cv" << std::endl;
        cv.notify_one();
    });

    std::cout << "starting wait" << std::endl;
    bool success = cv.wait_for(lock, std::chrono::seconds(10), [&ok]{ return ok; });
    std::cout << "finished waiting: " << success << std::endl;

    std::cout << "unlocking in main" << std::endl;
    lock.unlock();
    std::cout << "joining thread" << std::endl;
    t.join();
    std::cout << "thread joined" << std::endl;

    return 0;
}

这是我在Raspberry控制台上获得的标准g ++ linux版本的输出,用于比较:

RPi version:                linux version:
locking in main             locking in main
locked in main              locked in main
starting thread             starting thread
starting wait               starting wait
locking in thread           locking in thread
finished waiting: 0         locked in thread
unlocking in main           unlocking in thread
joining thread              signalling cv
locked in thread            finished waiting: 1
unlocking in thread         unlocking in main
signalling cv               joining thread
thread joined               thread joined

这让我相信代码很好,并且RaspberryPi交叉编译或标准库存在问题。我错过了什么,是否有解决这个问题的方法?

修改 这个问题首先在一个依赖于boost和socket.io-client的大项目中被注意到。我将main简化为问题中的那个,但没有删除其余的代码。它被编译和链接,如:

[...]
arm-linux-gnueabihf-g++ -std=c++1y -I%SRC_DIR%/rapidjson/include -I%SRC_DIR%/boost_1_65_0/install/include -I%SRC_DIR%/socket.io-client-cpp/build/include -O3 -g -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.o" -o "main.o" "../main.cpp"
[...]
arm-linux-gnueabihf-g++ -L%SRC_DIR%/boost_1_65_0/install-arm/lib -L%SRC_DIR%/socket.io-client-cpp/build-arm/lib/Release -L%SRC_DIR%/openssl/build-arm/lib -static -pthread -o "main" [...] ./main.o [...] -lsioclient -lboost_system -lssl -lcrypto -ldl

其他目标文件替换为[...],socket.io-client需要libssl。但是,如果我只使用arm-linux-gnueabihf-g++ -pthread -std=c++1y -O3 -g -Wall -o main1 main1.cpp编译已发布的片段,它在RaspberryPi上也能正常工作,所以它可能不是交叉编译工具的问题。是否有可能其中一个依赖项负责发生的事情?

2 个答案:

答案 0 :(得分:1)

看来我的链接器命令不正确,这可能导致pthread静态链接,这是由于交叉编译,不是RaspberryPi上系统所需的正确版本。根据我的问题编辑,我原来的错误(简化)链接命令就像:

arm-linux-gnueabihf-g++ -Lsome_dirs -static -pthread -o "main" ./main.o ./some_object_files -lsome_libs

在单个main.cpp文件的简单情况下,这样的链接选项在创建线程时报告了错误:terminate called after throwing an instance of 'std::system_error' what(): Enable multithreading to use std::thread: Operation not permitted。它最初让我失望,但实际上是一个有价值的线索。

要解决这个问题,我必须修改链接器命令以静态链接我需要静态链接的库,同时动态链接pthread,如下所示:

arm-linux-gnueabihf-g++ -o "main" ./main.o ./some_object_fiels -Lsome_dirs -Wl,-Bstatic -lsome_libs -Wl,-Bdynamic -ldl -pthread

答案 1 :(得分:0)

试试这个

std::cout << "locking in main" << std::endl;
std::unique_lock<std::mutex> lock(m);
std::cout << "locked in main" << std::endl;

std::cout << "starting thread" << std::endl;
std::thread t([&cv, &m, &ok]() {
    std::cout << "locking in thread" << std::endl;
    std::unique_lock<std::mutex> lock(m);
    std::cout << "locked in thread" << std::endl;
    ok = true;
    std::cout << "unlocking in thread" << std::endl;
    std::cout << "signalling cv" << std::endl;
    cv.notify_one();
});

std::cout << "starting wait" << std::endl;
while(!ok)
    cv.wait(lock);
std::cout << "finished waiting: " << ok << std::endl;

std::cout << "unlocking in main" << std::endl;
lock.unlock();
std::cout << "joining thread" << std::endl;
t.join();
std::cout << "thread joined" << std::endl;

此外,我认为您应该避免在线程内解锁互斥锁,因为在范围的最后,unique_lock会自动释放锁