Is it safe to mix boost::thread with C++11 std::mutex?
在通过boost启动其线程的程序中使用std::mutex及其同类是否安全?
(对我来说,使用std::thread不是我的选择,因为应用程序需要大量的堆栈空间,并且在某些平台上需要在创建时覆盖默认的堆栈大小。)
- 是的,这是安全的方法。 std::mutex只是程序和OS API调用之间的一层。也是boost::thread。
-
如果您担心,为什么不使用boost :: mutex?如果您使用boost本身的互斥锁,则将获得std :: mutex没有的所有功能。就像UpgradeLockable概念
-
@MrBin这对我来说听起来并不安全-在阅读了相关问题的答案之后就没有了。
-
@Mellester我正在尝试减少核心模块的"库占用",以便可以在其当前生态系统之外使用尽可能少的非标准库来使用它。从boost :: thread清除核心模块在这方面将是一个巨大的胜利,最显着的是因为它将消除链接到额外库的需求(与许多其他仅标头的boost组件相对)。
-
您必须真正坚持使用非常原始的对象进行锁定。您真的不能确定std :: lock(m1,m2)不会使用std :: thread :: sleep_until之类的东西,因为在boos :: thread中未定义这些东西。
-
尝试减少对Boost的依赖的好主意。但是您也不应该在应用程序内部设置堆栈大小,最有可能是针对您的特定平台的链接器选项(例如,示例)。然后,您可以切换到std::thread,而不必担心混合库。
-
您确定应用程序需要大量堆栈空间吗?我看不到一个应用程序占用了8MB的堆栈空间。
-
@rustyx在理想情况下,我们将依靠编译器或系统设置来控制堆栈大小;但不幸的是,在我们的目标平台之一上,只能从运行的应用程序(在您看来,OS X)控制其他线程的堆栈大小。
-
@fiorentinoing在OS X上,我们谈论的是每个线程512kiB的限制,而不是8MiB。我们确实看到了一些甚至4MiB都不够用的现实案例。 (此后软件已更改,我希望我们现在可以使用512kiB,但测试仍在进行中。)
-
@ChristophLipka我尝试使用valgrind(massif插件)来了解使用堆栈的地方,并更改为使用RAII进行堆放。你是这个吗
-
@fiorentinoing我是Windows骑师; valgrind超出了我的薪水范围;)但是,是的,我可能正在研究摆脱更多的堆栈结构。但是由于性能限制,它可能不会像通过简单的RAIIpackage器将其分配到堆上那样琐碎,因此我仍在尝试避免打开这种蠕虫病毒。
-
现在已经有了第一个测试结果,它们看起来非常有前途:在以前需要高达2 MiB的堆栈的情况下,我们现在省去了16 KiB。因此,除非在其他测试中出现意外情况,否则即使对于Mac OS X,默认堆栈大小也应适合所有人。
是的,您可以在使用boost::thread创建的线程中使用std::mutex。
启动线程(pthread_create,boost::thread,std::thread)的方式与您使用的同步原语正交(std,boost,Intel TBB,libatomic,等等。)。
否则,您将无法在一个应用程序中混合使用使用这些不同API的库。
低级同步原语(例如原子,互斥体和条件变量)可以放置在共享内存中,并由不同进程使用,而根本无需显式创建任何额外的线程。以及OS内核为您创建的主应用程序线程,无需使用任何用户空间API。
the application needs a lot of stack space, and on some platforms requires overriding the default stack size upon creation
std::thread使用pthread_create在支持POSIX的平台上创建线程。您的另一个选择是覆盖pthread_create,设置堆栈大小并调用原始的pthread_create。
一个有效的Linux示例(我无法访问MacOS进行尝试):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #include <cstdio>
#include <thread>
#include <dlfcn.h>
namespace {
size_t const STACK_SIZE = 8 * 1024 * 1024;
int pthread_create_override(pthread_t* thread, pthread_attr_t const* attr, void*(*start_routine)(void*), void* arg) noexcept {
std::printf("%s\
", __PRETTY_FUNCTION__);
pthread_attr_t attr2;
if(attr)
attr2 = *attr;
else
if(pthread_attr_init(&attr2))
std::abort();
size_t stacksize = 0;
pthread_attr_getstacksize(&attr2, &stacksize);
if(stacksize < STACK_SIZE) {
if(pthread_attr_setstacksize(&attr2, STACK_SIZE))
std::abort();
}
static auto const real_pthread_create = reinterpret_cast<decltype(&pthread_create)>(::dlsym(RTLD_NEXT,"pthread_create"));
int rc = real_pthread_create(thread, &attr2, start_routine, arg);
if(!attr)
pthread_attr_destroy(&attr2);
return rc;
}
} // namespace
extern"C" {
int pthread_create(pthread_t* thread, pthread_attr_t const* attr, void*(*start_routine)(void*), void* arg) {
return pthread_create_override(thread, attr, start_routine, arg);
}
} // namespace
int main() {
std::thread t([]() { std::printf("%s\
", __PRETTY_FUNCTION__); });
t.join();
} |
输出:
1 2
| int {anonymous}::pthread_create_override(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)
main()::<lambda()> |
- 已知ulimit和setrlimit方法都只影响Mac OS X上的主线程。
-
std::thread是否调用pthread_create-更不用说此调用是否以可以通过提供我自己的pthread_create来简单地覆盖的方式实现-最确定的是实现定义的,并依靠它保持实现方式在惹麻烦。
-
@ChristophLipka您可以在Mac OS系统上验证是否覆盖pthread_create是否可以解决您的问题?您的标准库很可能使用标准的pthread_create,因为std::thread被设计为Pthreadpackage器,而Mac OS X确实提供了此API。
-
您可以为std::thread被"设计为Pthreadpackage器"提供权威的信息吗?因为我很确定该标准不是专门为任何特定线程实现设计的package。 (而且不,我无法在"我的Mac OS系统"上进行验证,因为我自己没有这样的系统可供使用;更不用说Mac OS并不是我们唯一的目标平台。)
-
@ChristophLipka这是C线程模仿Pthread API的常识,对熟悉这两个API的任何人来说都是显而易见的。
-
如果std::thread模仿Pthread API,则线程属性在哪里?我在任何地方都看不到它们。
-
@ChristophLipka pubs.opengroup.org/onlinepubs/9699919799/help/codes.html#TSS:线程堆栈大小属性所描述的功能是可选的。所描述的功能也是对ISO C标准的扩展。