std::condition_variable::wait 没有释放对 RaspberryPi 的锁定
std::condition_variable::wait not releasing lock on RaspberryPi
我在 Ubuntu 上使用 git://github.com/raspberrypi/tools.[=35= 的工具为 RaspberryPi(3) 交叉编译了一个项目].我想使用 condition_variable
, but 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 上也能正常工作,所以这可能不是交叉编译工具的问题。是否有可能依赖项之一对正在发生的事情负责?
试试这个
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 会自动释放锁
看来我的 linker 命令不正确,这(可能)导致 pthread
被静态 linked,由于交叉编译,这是不正确的树莓派系统要求的版本。根据我的问题编辑,我原来的错误(简化)link 命令是这样的:
arm-linux-gnueabihf-g++ -Lsome_dirs -static -pthread -o "main" ./main.o ./some_object_files -lsome_libs
在单个 main.cpp 文件的简单情况下,此类 linking 选项在创建线程时报告错误:terminate called after throwing an instance of 'std::system_error' what(): Enable multithreading to use std::thread: Operation not permitted
。它最初让我失望,但实际上是一个有价值的线索。
为了解决这个问题,我不得不将 linker 命令修改为静态 link 库,我需要静态 linked,而 linking pthread 是动态的,像这样:
arm-linux-gnueabihf-g++ -o "main" ./main.o ./some_object_fiels -Lsome_dirs -Wl,-Bstatic -lsome_libs -Wl,-Bdynamic -ldl -pthread
我在 Ubuntu 上使用 git://github.com/raspberrypi/tools.[=35= 的工具为 RaspberryPi(3) 交叉编译了一个项目].我想使用 condition_variable
, but 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 上也能正常工作,所以这可能不是交叉编译工具的问题。是否有可能依赖项之一对正在发生的事情负责?
试试这个
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 会自动释放锁
看来我的 linker 命令不正确,这(可能)导致 pthread
被静态 linked,由于交叉编译,这是不正确的树莓派系统要求的版本。根据我的问题编辑,我原来的错误(简化)link 命令是这样的:
arm-linux-gnueabihf-g++ -Lsome_dirs -static -pthread -o "main" ./main.o ./some_object_files -lsome_libs
在单个 main.cpp 文件的简单情况下,此类 linking 选项在创建线程时报告错误:terminate called after throwing an instance of 'std::system_error' what(): Enable multithreading to use std::thread: Operation not permitted
。它最初让我失望,但实际上是一个有价值的线索。
为了解决这个问题,我不得不将 linker 命令修改为静态 link 库,我需要静态 linked,而 linking pthread 是动态的,像这样:
arm-linux-gnueabihf-g++ -o "main" ./main.o ./some_object_fiels -Lsome_dirs -Wl,-Bstatic -lsome_libs -Wl,-Bdynamic -ldl -pthread