C++ 不同的线程在 FreeBSD 10 上具有相同的线程 ID
C++ different threads have the same thread ID on FreeBSD 10
我在 FreeBSD 10 机器上使用 C++ 日志库,我 运行 在收到 sigint
.
时无法关闭线程
A 创建了一个 GitHub 项目用于测试 (link)。如果您在 FreeBSD 10 上构建它,请执行它并按 [ctrl+c] 它将终止。您可以在下面找到我使用的构建命令。
$ git clone git@github.com:tijme/free-bsd-thread-bug.git
$ cd free-bsd-thread-bug && mkdir -p cmake-build-debug && cd cmake-build-debug
$ cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER="/usr/local/bin/gcc6" -DCMAKE_CXX_COMPILER="/usr/local/bin/g++6"
$ make -dA
$ ./FreeBSDThreadBug
我使用的代码(也可以在 GitHub 存储库中找到)
/* main.cpp */
#include "Example.h"
#include <iostream>
#include <csignal>
#include <thread>
#include <chrono>
Example* example = new Example();
void onSignal(int signum)
{
delete example;
exit(0);
}
int main() {
signal(SIGINT, onSignal);
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
return 0;
}
/* Example.h */
#ifndef FREEBSDTHREADBUG_EXAMPLE_H
#define FREEBSDTHREADBUG_EXAMPLE_H
#include <thread>
#include <iostream>
#include <chrono>
class Example {
public:
Example();
~Example();
std::thread threadHandle;
void threadFunction();
};
#endif //FREEBSDTHREADBUG_EXAMPLE_H
/* Example.cpp */
#include "Example.h"
#include <thread>
#include <chrono>
Example::Example()
{
std::cout << "Main: starting thread" << std::endl;
threadHandle = std::thread(&Example::threadFunction, this);
std::cout << "Main: thread started" << std::endl;
}
Example::~Example()
{
std::cout << "THIS ID: " << std::this_thread::get_id() << std::endl;
std::cout << "THREAD ID: " << threadHandle.get_id() << std::endl;
std::cout << "Main: joining thread" << std::endl;
threadHandle.join();
std::cout << "Main: thread joined" << std::endl;
}
void Example::threadFunction() {
std::cout << "Thread: starting to sleep" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(2500));
std::cout << "Thread: sleep finished" << std::endl;
}
正确输出(例如在 MacOS Sierra 上):
如您所见,线程的 ID 正如预期的那样不同。
$ ./FreeBSDThreadBug
Main: starting thread
Main: thread started
Thread: starting to sleep
^C
THIS ID: 0x7fffa428a3c0
THREAD ID: 0x70000c044000
Main: joining thread
Thread: sleep finished
Main: thread joined
错误输出(终止,在 FreeBSD 10.3 上):
这里的线程 ID 是一样的,这很奇怪。
$ ./FreeBSDThreadBug
Main: starting thread
Main: thread started
Thread: starting to sleep
^C
THIS ID: 0x801c06800
THREAD ID: 0x801c06800
Main: joining thread
terminate called after throwing an instance of 'std::system_error'
what(): Resource deadlock avoided
Abort (core dumped)
核心转储
Core was generated by `FreeBSDThreadBug'.
Program terminated with signal SIGABRT, Aborted.
#0 0x00000008012d335a in thr_kill () from /lib/libc.so.7
[Current thread is 1 (LWP 100146)]
(gdb) bt full
#0 0x00000008012d335a in thr_kill () from /lib/libc.so.7
No symbol table info available.
#1 0x00000008012d3346 in raise () from /lib/libc.so.7
No symbol table info available.
#2 0x00000008012d32c9 in abort () from /lib/libc.so.7
No symbol table info available.
#3 0x0000000800ad8afd in __gnu_cxx::__verbose_terminate_handler () at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/vterminate.cc:95
terminating = true
t = <optimized out>
#4 0x0000000800ad5b48 in __cxxabiv1::__terminate (handler=<optimized out>) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/eh_terminate.cc:47
No locals.
#5 0x0000000800ad5bb1 in std::terminate () at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/eh_terminate.cc:57
No locals.
#6 0x0000000800ad5dc8 in __cxxabiv1::__cxa_throw (obj=obj@entry=0x80200e0a0, tinfo=0x800dd0bc0 <typeinfo for std::system_error>, dest=0x800b073b0 <std::system_error::~system_error()>)
at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/eh_throw.cc:87
globals = <optimized out>
#7 0x0000000800b04cd1 in std::__throw_system_error (__i=11) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/src/c++11/functexcept.cc:130
No locals.
#8 0x0000000800b0792c in std::thread::join (this=0x801c5c058) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/src/c++11/thread.cc:139
__e = <optimized out>
#9 0x00000000004016fc in Example::~Example (this=0x801c5c058, __in_chrg=<optimized out>) at /root/FreeBSDThreadBug/Example.cpp:18
No locals.
#10 0x00000000004010b7 in onSignal (signum=2) at /root/FreeBSDThreadBug/main.cpp:11
No locals.
#11 0x000000080082fb4a in ?? () from /lib/libthr.so.3
No symbol table info available.
#12 0x000000080082f22c in ?? () from /lib/libthr.so.3
No symbol table info available.
#13 <signal handler called>
No symbol table info available.
#14 0x00000008012efb5a in _nanosleep () from /lib/libc.so.7
No symbol table info available.
#15 0x000000080082cc4c in ?? () from /lib/libthr.so.3
No symbol table info available.
#16 0x000000000040155d in std::this_thread::sleep_for<long, std::ratio<1l, 1000l> > (__rtime=...) at /usr/local/lib/gcc6/include/c++/thread:322
__s = {__r = 2}
__ns = {__r = 500000000}
__ts = {tv_sec = 1, tv_nsec = 126917539}
#17 0x000000000040177a in Example::threadFunction (this=0x801c5c058) at /root/FreeBSDThreadBug/Example.cpp:24
No locals.
#18 0x0000000000402432 in std::__invoke_impl<void, void (Example::* const&)(), Example*>(std::__invoke_memfun_deref, void (Example::* const&)(), Example*&&) (
__f=@0x801c5e050: (void (Example::*)(Example * const)) 0x40172c <Example::threadFunction()>, __t=<unknown type in /root/FreeBSDThreadBug/cmake-build-debug/FreeBSDThreadBug, CU 0x552f, DIE 0xb2d7>)
at /usr/local/lib/gcc6/include/c++/functional:227
No locals.
#19 0x00000000004023bf in std::__invoke<void (Example::* const&)(), Example*>(void (Example::* const&)(), Example*&&) (__fn=@0x801c5e050: (void (Example::*)(Example * const)) 0x40172c <Example::threadFunction()>,
__args#0=<unknown type in /root/FreeBSDThreadBug/cmake-build-debug/FreeBSDThreadBug, CU 0x552f, DIE 0xb2d7>) at /usr/local/lib/gcc6/include/c++/functional:251
No locals.
#20 0x0000000000402370 in std::_Mem_fn_base<void (Example::*)(), true>::operator()<Example*>(Example*&&) const (this=0x801c5e050,
__args#0=<unknown type in /root/FreeBSDThreadBug/cmake-build-debug/FreeBSDThreadBug, CU 0x552f, DIE 0xb2d7>) at /usr/local/lib/gcc6/include/c++/functional:604
No locals.
#21 0x000000000040233b in std::_Bind_simple<std::_Mem_fn<void (Example::*)()> (Example*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) (this=0x801c5e048) at /usr/local/lib/gcc6/include/c++/functional:1391
No locals.
#22 0x0000000000402289 in std::_Bind_simple<std::_Mem_fn<void (Example::*)()> (Example*)>::operator()() (this=0x801c5e048) at /usr/local/lib/gcc6/include/c++/functional:1380
No locals.
#23 0x0000000000402268 in std::thread::_State_impl<std::_Bind_simple<std::_Mem_fn<void (Example::*)()> (Example*)> >::_M_run() (this=0x801c5e040) at /usr/local/lib/gcc6/include/c++/thread:196
No locals.
#24 0x0000000800b0769f in std::execute_native_thread_routine (__p=0x801c5e040) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/src/c++11/thread.cc:83
__t = std::unique_ptr<std::thread::_State> containing 0x801c5e040
#25 0x000000080082a855 in ?? () from /lib/libthr.so.3
No symbol table info available.
#26 0x0000000000000000 in ?? ()
No symbol table info available.
Backtrace stopped: Cannot access memory at address 0x7fffdfffe000
系统信息
$ freebsd-version
10.3-RELEASE
$ /usr/local/bin/gcc6 --version
gcc6 (FreeBSD Ports Collection) 6.3.0
$ /usr/local/bin/g++6 --version
g++6 (FreeBSD Ports Collection) 6.3.0
$ cmake --version
cmake version 3.7.2
我创建的原始问题可以在 GitHub (link) 上找到,但是目前还没有修复。
我希望有人能帮我解决这个问题。提前致谢。
这不是错误,这是一个功能。
您无法保证信号将被传送到哪里,并且您可以在信号处理程序中执行的操作受到限制。
请参阅 sigaction(3)
以了解有关您可以执行的操作(以及您不能执行任何其他操作)的详细信息。您的程序正在做许多信号处理程序中不允许的事情。
正确的做法是在您的程序中发出其他信号并 return 来自信号处理程序。这样做的一个示例技术是 "self pipe trick"。创建一个管道并在两端保留一个手柄。在正常 I/O 处理中从一端读取。如果收到信号,在信号处理程序中,向管道的另一端写入一个字节 return。当从管道读取字节时,您知道信号已经到达,您可以安全地进行扩展处理。
更新:
正如 Michael Burr 所指出的,您可以使用 pthread_sigmask(3)
阻止特定线程接收特定信号。但是,要解决这里的潜在问题,您仍然需要不在信号处理程序中进行工作。
我在 FreeBSD 10 机器上使用 C++ 日志库,我 运行 在收到 sigint
.
A 创建了一个 GitHub 项目用于测试 (link)。如果您在 FreeBSD 10 上构建它,请执行它并按 [ctrl+c] 它将终止。您可以在下面找到我使用的构建命令。
$ git clone git@github.com:tijme/free-bsd-thread-bug.git
$ cd free-bsd-thread-bug && mkdir -p cmake-build-debug && cd cmake-build-debug
$ cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER="/usr/local/bin/gcc6" -DCMAKE_CXX_COMPILER="/usr/local/bin/g++6"
$ make -dA
$ ./FreeBSDThreadBug
我使用的代码(也可以在 GitHub 存储库中找到)
/* main.cpp */
#include "Example.h"
#include <iostream>
#include <csignal>
#include <thread>
#include <chrono>
Example* example = new Example();
void onSignal(int signum)
{
delete example;
exit(0);
}
int main() {
signal(SIGINT, onSignal);
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
return 0;
}
/* Example.h */
#ifndef FREEBSDTHREADBUG_EXAMPLE_H
#define FREEBSDTHREADBUG_EXAMPLE_H
#include <thread>
#include <iostream>
#include <chrono>
class Example {
public:
Example();
~Example();
std::thread threadHandle;
void threadFunction();
};
#endif //FREEBSDTHREADBUG_EXAMPLE_H
/* Example.cpp */
#include "Example.h"
#include <thread>
#include <chrono>
Example::Example()
{
std::cout << "Main: starting thread" << std::endl;
threadHandle = std::thread(&Example::threadFunction, this);
std::cout << "Main: thread started" << std::endl;
}
Example::~Example()
{
std::cout << "THIS ID: " << std::this_thread::get_id() << std::endl;
std::cout << "THREAD ID: " << threadHandle.get_id() << std::endl;
std::cout << "Main: joining thread" << std::endl;
threadHandle.join();
std::cout << "Main: thread joined" << std::endl;
}
void Example::threadFunction() {
std::cout << "Thread: starting to sleep" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(2500));
std::cout << "Thread: sleep finished" << std::endl;
}
正确输出(例如在 MacOS Sierra 上):
如您所见,线程的 ID 正如预期的那样不同。
$ ./FreeBSDThreadBug
Main: starting thread
Main: thread started
Thread: starting to sleep
^C
THIS ID: 0x7fffa428a3c0
THREAD ID: 0x70000c044000
Main: joining thread
Thread: sleep finished
Main: thread joined
错误输出(终止,在 FreeBSD 10.3 上):
这里的线程 ID 是一样的,这很奇怪。
$ ./FreeBSDThreadBug
Main: starting thread
Main: thread started
Thread: starting to sleep
^C
THIS ID: 0x801c06800
THREAD ID: 0x801c06800
Main: joining thread
terminate called after throwing an instance of 'std::system_error'
what(): Resource deadlock avoided
Abort (core dumped)
核心转储
Core was generated by `FreeBSDThreadBug'.
Program terminated with signal SIGABRT, Aborted.
#0 0x00000008012d335a in thr_kill () from /lib/libc.so.7
[Current thread is 1 (LWP 100146)]
(gdb) bt full
#0 0x00000008012d335a in thr_kill () from /lib/libc.so.7
No symbol table info available.
#1 0x00000008012d3346 in raise () from /lib/libc.so.7
No symbol table info available.
#2 0x00000008012d32c9 in abort () from /lib/libc.so.7
No symbol table info available.
#3 0x0000000800ad8afd in __gnu_cxx::__verbose_terminate_handler () at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/vterminate.cc:95
terminating = true
t = <optimized out>
#4 0x0000000800ad5b48 in __cxxabiv1::__terminate (handler=<optimized out>) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/eh_terminate.cc:47
No locals.
#5 0x0000000800ad5bb1 in std::terminate () at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/eh_terminate.cc:57
No locals.
#6 0x0000000800ad5dc8 in __cxxabiv1::__cxa_throw (obj=obj@entry=0x80200e0a0, tinfo=0x800dd0bc0 <typeinfo for std::system_error>, dest=0x800b073b0 <std::system_error::~system_error()>)
at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/eh_throw.cc:87
globals = <optimized out>
#7 0x0000000800b04cd1 in std::__throw_system_error (__i=11) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/src/c++11/functexcept.cc:130
No locals.
#8 0x0000000800b0792c in std::thread::join (this=0x801c5c058) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/src/c++11/thread.cc:139
__e = <optimized out>
#9 0x00000000004016fc in Example::~Example (this=0x801c5c058, __in_chrg=<optimized out>) at /root/FreeBSDThreadBug/Example.cpp:18
No locals.
#10 0x00000000004010b7 in onSignal (signum=2) at /root/FreeBSDThreadBug/main.cpp:11
No locals.
#11 0x000000080082fb4a in ?? () from /lib/libthr.so.3
No symbol table info available.
#12 0x000000080082f22c in ?? () from /lib/libthr.so.3
No symbol table info available.
#13 <signal handler called>
No symbol table info available.
#14 0x00000008012efb5a in _nanosleep () from /lib/libc.so.7
No symbol table info available.
#15 0x000000080082cc4c in ?? () from /lib/libthr.so.3
No symbol table info available.
#16 0x000000000040155d in std::this_thread::sleep_for<long, std::ratio<1l, 1000l> > (__rtime=...) at /usr/local/lib/gcc6/include/c++/thread:322
__s = {__r = 2}
__ns = {__r = 500000000}
__ts = {tv_sec = 1, tv_nsec = 126917539}
#17 0x000000000040177a in Example::threadFunction (this=0x801c5c058) at /root/FreeBSDThreadBug/Example.cpp:24
No locals.
#18 0x0000000000402432 in std::__invoke_impl<void, void (Example::* const&)(), Example*>(std::__invoke_memfun_deref, void (Example::* const&)(), Example*&&) (
__f=@0x801c5e050: (void (Example::*)(Example * const)) 0x40172c <Example::threadFunction()>, __t=<unknown type in /root/FreeBSDThreadBug/cmake-build-debug/FreeBSDThreadBug, CU 0x552f, DIE 0xb2d7>)
at /usr/local/lib/gcc6/include/c++/functional:227
No locals.
#19 0x00000000004023bf in std::__invoke<void (Example::* const&)(), Example*>(void (Example::* const&)(), Example*&&) (__fn=@0x801c5e050: (void (Example::*)(Example * const)) 0x40172c <Example::threadFunction()>,
__args#0=<unknown type in /root/FreeBSDThreadBug/cmake-build-debug/FreeBSDThreadBug, CU 0x552f, DIE 0xb2d7>) at /usr/local/lib/gcc6/include/c++/functional:251
No locals.
#20 0x0000000000402370 in std::_Mem_fn_base<void (Example::*)(), true>::operator()<Example*>(Example*&&) const (this=0x801c5e050,
__args#0=<unknown type in /root/FreeBSDThreadBug/cmake-build-debug/FreeBSDThreadBug, CU 0x552f, DIE 0xb2d7>) at /usr/local/lib/gcc6/include/c++/functional:604
No locals.
#21 0x000000000040233b in std::_Bind_simple<std::_Mem_fn<void (Example::*)()> (Example*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) (this=0x801c5e048) at /usr/local/lib/gcc6/include/c++/functional:1391
No locals.
#22 0x0000000000402289 in std::_Bind_simple<std::_Mem_fn<void (Example::*)()> (Example*)>::operator()() (this=0x801c5e048) at /usr/local/lib/gcc6/include/c++/functional:1380
No locals.
#23 0x0000000000402268 in std::thread::_State_impl<std::_Bind_simple<std::_Mem_fn<void (Example::*)()> (Example*)> >::_M_run() (this=0x801c5e040) at /usr/local/lib/gcc6/include/c++/thread:196
No locals.
#24 0x0000000800b0769f in std::execute_native_thread_routine (__p=0x801c5e040) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/src/c++11/thread.cc:83
__t = std::unique_ptr<std::thread::_State> containing 0x801c5e040
#25 0x000000080082a855 in ?? () from /lib/libthr.so.3
No symbol table info available.
#26 0x0000000000000000 in ?? ()
No symbol table info available.
Backtrace stopped: Cannot access memory at address 0x7fffdfffe000
系统信息
$ freebsd-version
10.3-RELEASE
$ /usr/local/bin/gcc6 --version
gcc6 (FreeBSD Ports Collection) 6.3.0
$ /usr/local/bin/g++6 --version
g++6 (FreeBSD Ports Collection) 6.3.0
$ cmake --version
cmake version 3.7.2
我创建的原始问题可以在 GitHub (link) 上找到,但是目前还没有修复。
我希望有人能帮我解决这个问题。提前致谢。
这不是错误,这是一个功能。
您无法保证信号将被传送到哪里,并且您可以在信号处理程序中执行的操作受到限制。
请参阅 sigaction(3)
以了解有关您可以执行的操作(以及您不能执行任何其他操作)的详细信息。您的程序正在做许多信号处理程序中不允许的事情。
正确的做法是在您的程序中发出其他信号并 return 来自信号处理程序。这样做的一个示例技术是 "self pipe trick"。创建一个管道并在两端保留一个手柄。在正常 I/O 处理中从一端读取。如果收到信号,在信号处理程序中,向管道的另一端写入一个字节 return。当从管道读取字节时,您知道信号已经到达,您可以安全地进行扩展处理。
更新:
正如 Michael Burr 所指出的,您可以使用 pthread_sigmask(3)
阻止特定线程接收特定信号。但是,要解决这里的潜在问题,您仍然需要不在信号处理程序中进行工作。