TSAN thread race error detected with Boost intrusive_ptr use - c++

Below code generates a TSAN error(race condition).
Is this a valid error ? or a false positive ?
Object is destroyed only after ref count becomes zero(after all other thread memory operations are visible - with atomic_thread_fence)
If I use a std::shared_ptr instead of boost::intrusive_ptr, then TSAN error disappears.
Since both threads use the object as read-only, I presume this should be safe.
If this is a valid error how do I fix it ?
gcc version - 7.3.1 boost version - 1.72.0
compile command : "g++ -ggdb -I /usr/local/boost_1_72_0 -O3 -fsanitize=thread TSan_Intr_Ptr.cpp -lpthread
"
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include <boost/smart_ptr/detail/spinlock.hpp>
#include <boost/atomic.hpp>
#include <thread>
#include <iostream>
#include <vector>
#include <atomic>
#include <unistd.h>
using namespace std;
struct Shared
{
mutable boost::atomic<int> refcount_;
//From https://www.boost.org/doc/libs/1_72_0/doc/html/atomic/usage_examples.html
friend void intrusive_ptr_add_ref(const Shared * x)
{
x->refcount_.fetch_add(1, boost::memory_order_relaxed);
}
friend void intrusive_ptr_release(const Shared* x)
{
if (x->refcount_.fetch_sub(1, boost::memory_order_release) == 1)
{
boost::atomic_thread_fence(boost::memory_order_acquire);
delete x;
}
}
};
vector<boost::intrusive_ptr<Shared const>> g_vec;
boost::detail::spinlock g_lock = BOOST_DETAIL_SPINLOCK_INIT;
void consumer()
{
while(true)
{
g_lock.lock();
g_vec.clear();
g_lock.unlock();
usleep(10);
}
}
int main()
{
thread thd(consumer);
while(true)
{
boost::intrusive_ptr<Shared const> p(new Shared);
g_lock.lock();
g_vec.push_back(p);
g_lock.unlock();
usleep(1);
}
return 0;
}
TSAN Error
WARNING: ThreadSanitizer: data race (pid=14513)
Write of size 8 at 0x7b0400000010 by main thread:
#0 operator delete(void*) <null> (libtsan.so.0+0x00000006fae4)
#1 intrusive_ptr_release(Shared const*) /Test/TSan_Intr_Ptr_Min.cpp:25 (a.out+0x000000401195)
#2 boost::intrusive_ptr<Shared const>::~intrusive_ptr() /boost_1_72_0/boost/smart_ptr/intrusive_ptr.hpp:98 (a.out+0x000000401195)
#3 main /x01/exch/Test/TSan_Intr_Ptr_Min.cpp:51 (a.out+0x000000401195)
Previous atomic write of size 4 at 0x7b0400000010 by thread T1:
#0 __tsan_atomic32_fetch_sub <null> (libtsan.so.0+0x00000006576f)
#1 boost::atomics::detail::gcc_atomic_operations<4ul, true>::fetch_sub(unsigned int volatile&, unsigned int, boost::memory_order) /boost_1_72_0/boost/atomic/detail/ops_gcc_atomic.hpp:116 (a.out+0x000000401481)
#2 boost::atomics::detail::base_atomic<int, int>::fetch_sub(int, boost::memory_order) volatile /usr/local/boost_1_72_0/boost/atomic/detail/atomic_template.hpp:348 (a.out+0x000000401481)
#3 intrusive_ptr_release(Shared const*) /Test/TSan_Intr_Ptr_Min.cpp:22 (a.out+0x000000401481)
...

it seems using memory_order_acq_rel resolves the issue. (May be https://www.boost.org/doc/libs/1_72_0/doc/html/atomic/usage_examples.html example is in-correct)
friend void intrusive_ptr_add_ref(const Shared * x)
{
x->refcount_.fetch_add(1, boost::memory_order_acq_rel);
}
friend void intrusive_ptr_release(const Shared* x)
{
if (x->refcount_.fetch_sub(1, boost::memory_order_acq_rel) == 1)
{
delete x;
}
}

Related

C++11 multithreading: Valgrind uninitialized value(s) warning

I have compiled the following dummy program under Linux using gcc 8.2.1:
#include <iostream>
#include <mutex>
#include <thread>
struct Foo
{
void start() {
thread = std::thread(&Foo::run, this);
}
void stop() {
mutex.lock();
done = true;
mutex.unlock();
thread.join();
}
void run() {
bool tmp;
for (;;) {
mutex.lock();
tmp = done;
mutex.unlock();
if (tmp)
break;
}
}
std::thread thread;
std::mutex mutex;
bool done;
};
int main()
{
Foo foo;
std::cout << "starting...\n";
foo.start();
std::cout << "stopping...\n";
foo.stop();
std::cout << "done\n";
}
If I subsequently run it under valgrind 3.14.0, I receive the following warning:
==30060== Thread 2:
==30060== Conditional jump or move depends on uninitialised value(s)
==30060== at 0x1095F3: Foo::run() (in /.../a.out)
==30060== by 0x109AAE: void std::__invoke_impl<void, void (Foo::*)(), Foo*>(std::__invoke_memfun_deref, void (Foo::*&&)(), Foo*&&) (in /.../a.out)
==30060== by 0x109771: std::__invoke_result<void (Foo::*)(), Foo*>::type std::__invoke<void (Foo::*)(), Foo*>(void (Foo::*&&)(), Foo*&&) (in /.../a.out)
==30060== by 0x10A012: decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (Foo::*)(), Foo*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) (in /.../a.out)
==30060== by 0x109FB8: std::thread::_Invoker<std::tuple<void (Foo::*)(), Foo*> >::operator()() (in /.../a.out)
==30060== by 0x109F8D: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (Foo::*)(), Foo*> > >::_M_run() (in /.../a.out)
==30060== by 0x496A062: execute_native_thread_routine (thread.cc:80)
==30060== by 0x4894A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==30060== by 0x4CD7A42: clone (in /usr/lib/libc-2.28.so)
I am not completely sure what is causing this, I have written this snippet in hopes of diagnosing a bug in a more complicated class (that I cannot post here) I am currently working on and which produces exceptions when calling the equivalent of Foo::stop(). Does the valgrind warning imply some serious misunderstanding of the C++ threading interface on my part? And assuming for a moment that Foo::run would actually do something useful, how could I fix this program while keeping Foo's interface the way it is?
What is the initial value of bool done; ? It is indeterminate (some garbage value), so your thread (run) can be stopped without calling stop method.
done must be initialized:
//...
std::mutex mutex;
bool done = false; // <--

clang-linux: reporting CFI errors without crashing. ftrap-function and -O2

I'm trying to use -ftrap-function flag from clang manual to catch CFI (call frame information) errors in a custom handler.
Here is a basic example generating a CFI error:
#include <stdio.h>
#include <stdlib.h>
__attribute__((used)) extern "C" void CatchCfi() {
printf("catched\n");
}
struct Foo {
Foo(const char* s) : command(s) {}
virtual ~Foo() {}
void fooStuff() { printf("fooStuff\n"); }
const char* command;
};
struct Bar {
Bar(const char* s) : name(s) {}
virtual ~Bar() {}
void barStuff() { printf("barStuff\n"); }
const char* name;
};
enum class WhichObject { FooObject, BarObject };
static void* allocator(WhichObject w, const char* arg) {
switch (w) {
case WhichObject::FooObject:
return new Foo(arg);
case WhichObject::BarObject:
return new Bar(arg);
}
}
int main(int argc, const char* argv[]) {
void* ptr = nullptr;
(void)(argc);
(void)(argv);
ptr = allocator(WhichObject::BarObject, "system(\"/bin/sh\")");
Foo* fooptr = static_cast<Foo*>(ptr);
fooptr->fooStuff();
printf("not printed when compiled with -O2\n");
return 0;
}
I build it with these CFI related clang options:
-ftrap-function=CatchCfi -fsanitize=cfi-vcall -fvisibility=hidden -fsanitize=cfi-derived-cast -fsanitize=cfi-unrelated-cast -flto=thin
When this example is built without optimization it works as I want. Output:
catched
fooStuff
not printed when compiled with -O2
The problem appear when I build it with -O2 option:
catched
Trace/breakpoint trap (core dumped)
GDB shows that the program is receiving SIGTRAP just after CatchCfi returns:
(gdb) r
Starting program: /home/romex/browser/src/out/debug/hello_cfi
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
catched
Program received signal SIGTRAP, Trace/breakpoint trap.
0x000000000020118a in ?? ()
(gdb) bt
#0 0x000000000020118a in ?? ()
#1 0x00000000002010f0 in frame_dummy ()
#2 0x00007ffff748e830 in __libc_start_main (main=0x201180 <main(int, char const**)>, argc=1, argv=0x7fffffffde18, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
stack_end=0x7fffffffde08) at ../csu/libc-start.c:291
#3 0x0000000000201029 in _start ()
Warning: the current language does not match this frame.
(gdb)
How to fix that?
I'm wondering if somebody has a success story dealing with ftrap-function flag? May be there is some specific optimization flag fixing this error?
Thanks.
I've updated your code so it works as expected. My environment does not raise SIGTRAP, thus I inserted __builtin_trap() call. As mentioned #YSC it is UB. The program can not continue after your trap function returns, you must restore the program to well known good state before SIGTRAP raised.
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
jmp_buf env;
__attribute__((used)) extern "C" void CatchCfi() {
printf("catched\n");
longjmp(env, 1);
}
struct Foo {
Foo(const char* s) : command(s) {}
virtual ~Foo() {}
void fooStuff() { printf("fooStuff\n"); }
const char* command;
};
struct Bar {
Bar(const char* s) : name(s) {}
virtual ~Bar() {}
void barStuff() { printf("barStuff\n"); }
const char* name;
};
enum class WhichObject { FooObject, BarObject };
static void* allocator(WhichObject w, const char* arg) {
switch (w) {
case WhichObject::FooObject:
return new Foo(arg);
case WhichObject::BarObject:
return new Bar(arg);
}
}
int main(int argc, const char* argv[]) {
void* ptr = nullptr;
(void)(argc);
(void)(argv);
ptr = allocator(WhichObject::BarObject, "system(\"/bin/sh\")");
int val = setjmp(env);
if (!val) {
Foo* fooptr = static_cast<Foo*>(ptr);
fooptr->fooStuff();
__builtin_trap();
}
printf("not printed when compiled with -O2\n");
return 0;
}
Since ptr is a pointer to a Bar,
Foo* fooptr = static_cast<Foo*>(ptr);
fooptr->fooStuff();
is undefined behavior and the compiler is not compelled to work as you expect him to.

Could not compile c++ program with threads support on AIX with GCC compiler 4.7.3

I have problem when compiling code below on aix machine with gcc compiler (version 4.7.3):
SomeThread.h
#ifndef SomeThread_H
#define SomeThread_H
class SomeThread {
public:
SomeThread(void);
virtual ~SomeThread(void);
void runThread();
}; // SomeThread
#endif // _SomeThread_H_
SomeThread.cpp
#include "SomeThread.h"
#include <thread>
#include <iostream>
using namespace std;
namespace {
void foo_thread_function() {
for (int i = 0; i < 10; ++i) {
cout << "Some threaded text" << endl;
}
}
}
SomeThread::SomeThread() {
} // SomeThread
SomeThread::~SomeThread() {
} // ~SomeThread
void SomeThread::runThread() {
thread foo_thread_01(foo_thread_function);
thread foo_thread_02(foo_thread_function);
thread foo_thread_03(foo_thread_function);
foo_thread_01.join();
foo_thread_02.join();
foo_thread_03.join();
}
The error which I get is following:
SomeThread.cpp: In member function 'void SomeThread::runThread()':
SomeThread.cpp:58:4: error: reference to 'thread' is ambiguous
In file included from /usr/include/sys/ptrace.h:28:0,
from /usr/include/sys/proc.h:42,
from /usr/include/sys/pri.h:43,
from /usr/include/sys/sched.h:38,
from /usr/include/sched.h:51,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include-fixed/pthread.h:76,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/powerpc-ibm-aix7.1.0.0/pthread/ppc64/bits/gthr-posix.h:41,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/powerpc-ibm-aix7.1.0.0/pthread/ppc64/bits/gthr-default.h:30,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/powerpc-ibm-aix7.1.0.0/pthread/ppc64/bits/gthr.h:150,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/ext/atomicity.h:34,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/memory:75,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/thread:40,
from SomeThread.cpp:5:
/usr/include/sys/thread.h:105:8: error: candidates are: struct thread
In file included from SomeThread.cpp:5:0:
/opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/thread:60:9: error: class std::thread
SomeThread.cpp:58:11: error: expected ';' before 'foo_thread_01'
SomeThread.cpp:59:4: error: reference to 'thread' is ambiguous
In file included from /usr/include/sys/ptrace.h:28:0,
from /usr/include/sys/proc.h:42,
from /usr/include/sys/pri.h:43,
from /usr/include/sys/sched.h:38,
from /usr/include/sched.h:51,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include-fixed/pthread.h:76,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/powerpc-ibm-aix7.1.0.0/pthread/ppc64/bits/gthr-posix.h:41,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/powerpc-ibm-aix7.1.0.0/pthread/ppc64/bits/gthr-default.h:30,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/powerpc-ibm-aix7.1.0.0/pthread/ppc64/bits/gthr.h:150,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/ext/atomicity.h:34,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/memory:75,
from /opt/freeware/lib/gcc/powerpc-ibm-aix7.1.0.0/4.7.3/include/c++/thread:40,
from SomeThread.cpp:5:
I compile the above files with following command line:
g++ -maix64 -DTARGET=target_thread -DGENDATE=04_01_2017 -DTT_LIB_DLLSUFFIX=\".so\" -DOSNAME=\"AIX\" -D_GNU_SOURCE -D_REENTRANT -DAIX -Wno-deprecated -I. -std=gnu++11 -maix64 -pthread -mminimal-toc -fpermissive -Wno-write-strings -Winvalid-offsetof -O3 -c -oSomeThread.o SomeThread.cpp
The problem is, that there are multiple implementations of thread with your compiler options and includes. Maybe it would be just enough to correct the code to this.
SomeThread.cpp
#include "SomeThread.h"
#include <thread>
#include <iostream>
//Stop using namespace std, please
namespace SomeNamespace {
void foo_thread_function() {
for (int i = 0; i < 10; ++i) {
cout << "Some threaded text" << endl;
}
}
}
SomeThread::SomeThread() {
} // SomeThread
SomeThread::~SomeThread() {
} // ~SomeThread
void SomeThread::runThread() {
std::thread foo_thread_01(SomeNamespace::foo_thread_function);
std::thread foo_thread_02(SomeNamespace::foo_thread_function);
std::thread foo_thread_03(SomeNamespace::foo_thread_function);
foo_thread_01.join();
foo_thread_02.join();
foo_thread_03.join();
}
Ambiguous means that there are multiple interpretations of the same word.
Example:
namespace Bla{
struct SomeStruct{
}
}
namespace Blub{
struct SomeStruct{
}
}
int main(){
using namespace Bla;
using namespace Blub;
SomeStruct ImAmbiguous; // Problem now, which struct should the compiler choose now?
Bla::SomeStruct structFromBla; //Now the compiler knows which struct should be choosen
return 0;
}

asio high_resolution_timer segmentation fault in async_wait

I have implemented a task queue with priority from asio examples and a timer class which use this queue. Here is the code:
priority_task_queue.h
class handler_priority_queue
{
private:
class queued_handler{
private:
size_t _priority;
std::function<void()> _function;
public:
queued_handler(size_t p, std::function<void()> f): _priority(p), _function(f){}
friend bool operator<(const queued_handler& a, const queued_handler& b){
return a._priority < b._priority;
}
void operator()() {
_function();
}
};
std::priority_queue<queued_handler> _handlers;
public:
// A generic wrapper class for handlers to allow the invocation to be hooked.
template <typename Handler> class wrapped_handler
{
private:
handler_priority_queue& _queue;
size_t _priority;
Handler _handler;
public:
handler_priority_queue& queue() {return _queue;}
size_t priority() {return _priority;}
wrapped_handler(handler_priority_queue& q, size_t p, Handler h)
: _queue(q), _priority(p), _handler(h){}
template <typename ...Args>
void operator()(Args&&... args){
_handler(std::forward<Args>(args)...);
}
};
template <typename Handler> wrapped_handler<Handler> wrap(size_t priority, Handler handler){
return wrapped_handler<Handler>(*this, priority, handler);
}
void add(size_t priority, std::function<void()> function);
void execute_all();
void execute_one();
bool empty();
};
// Custom invocation hook for wrapped handlers.
template <typename Function, typename Handler>
void asio_handler_invoke(Function f, handler_priority_queue::wrapped_handler<Handler>* h){
h->queue().add(h->priority(), f);
std::cout<<"LLAMANDO AL INVOKE"<<std::endl; //BORRAR!!
}
class C_priority_task_queue{
private:
asio::io_service& _io;
handler_priority_queue _pri_queue;
public:
template <typename Handler> handler_priority_queue::wrapped_handler<Handler> wrap(int priority, Handler handler){
return _pri_queue.wrap(priority, handler);
}
explicit C_priority_task_queue(asio::io_service& io): _io(io){}
C_priority_task_queue(C_priority_task_queue const&) = delete;
C_priority_task_queue& operator =(C_priority_task_queue const&) = delete;
asio::io_service& io() {return _io;}
void run();
};
priority_task_queue.cpp
void handler_priority_queue::add(size_t priority, std::function<void()> function){
_handlers.push(queued_handler(priority, function));
}
void handler_priority_queue::execute_one(){
if(!_handlers.empty()){
queued_handler handler = _handlers.top();
handler();
_handlers.pop();
}
}
bool handler_priority_queue::empty(){
return _handlers.empty();
}
void C_priority_task_queue::run(){
while (_io.run_one())
{
_io.poll();
while(!_pri_queue.empty())
{
_io.poll();
_pri_queue.execute_one();
}
}
}
base_timer.h
class C_timer {
private:
asio::high_resolution_timer _timer;
uint8_t _timer_id;
C_priority_task_queue& _prio_queue;
void timer_handler_internal(const asio::error_code& e, uint8_t timer_id, const uint64_t sched_time);
virtual void timer_handler(const uint64_t sched_time)=0;
public:
size_t _priority;
explicit C_timer(C_priority_task_queue& prio_queue, size_t priority);
virtual ~C_timer();
void set_timer(uint64_t sched_time);
int cancel();
};
base_timer.cpp
C_timer::C_timer(C_priority_task_queue& prio_queue, size_t priority):
_timer(prio_queue.io()), _timer_id(0), _prio_queue(prio_queue), _priority(priority){}
C_timer::~C_timer(){}
void C_timer::set_timer(uint64_t sched_time){
++_timer_id;
_timer.expires_at(std::chrono::time_point<std::chrono::high_resolution_clock>(std::chrono::milliseconds(sched_time)));
_timer.async_wait(_prio_queue.wrap(_priority, std::bind(&C_timer::timer_handler_internal, this,
std::placeholders::_1/*error*/, _timer_id, sched_time)));
}
int C_timer::cancel(){
++_timer_id;
return _timer.cancel();
}
void C_timer::timer_handler_internal(const asio::error_code& e, uint8_t timer_id,
const uint64_t sched_time){
if(e==asio::error::operation_aborted || timer_id != _timer_id){
return;
}
timer_handler(sched_time);
}
test class
class C_timer_test: public C_timer{
private:
int _period;
virtual void timer_handler(const uint64_t sched_time) override{
std::cout<<"timer fired"<<std::endl;
uint64_t current_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
set_timer(current_time + _period);
}
public:
C_timer_test(C_priority_task_queue& prio_queue, int priority, int period):C_timer(prio_queue, priority), _periodo(period){}
virtual ~C_timer_test(){}
void run(uint64_t delay=0){
uint64_t time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
set_timer(time + delay);
}
};
The problem is if I execute this :
int main()
{
asio::io_service io;
C_priority_task_queue prio_queue(io);
asio::io_service::work w(io);
C_timer_test ti1(prio_queue, 0, 2000);
ti1.run();
prio_queue.run();
return 0;
}
I get a segmentation fault.
However, if I execute the following code it works fine:
int main()
{
asio::io_service io;
C_priority_task_queue prio_queue(io);
asio::high_resolution_timer _timer1(io);
asio::io_service::work w(io);
C_timer_test ti1(prio_queue, 0, 2000);
ti1.run();
prio_queue.run();
return 0;
}
The only diference between both piece of code is in the second main I have added the following line asio::high_resolution_timer _timer1(io); that I haven't use in any place.
Debugging the program I have found that the signal is raising in this line:
func_(&owner, this, ec, bytes_transferred); in file task_io_service_operation.hpp
I am using asio version 1.10.6.
Any suggestion that what could be happening?
The backtrace from gdb:
gdb ./main
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
This GDB was configured as "i686-linux-gnu".
(gdb) r
[libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x0805f0d4 in ?? ()
(gdb) backtrace
#0 0x0805f0d4 in ?? ()
#1 0x080529fb in asio::detail::task_io_service::do_run_one (this=0x805f030, lock=..., this_thread=..., ec=...) at /src/cpp/external_lib/asio/include/asio/detail/impl/task_io_service.ipp:371
#2 0x080526ce in asio::detail::task_io_service::run_one (this=0x805f030, ec=...) at /src/cpp/external_lib/asio/include/asio/detail/impl/task_io_service.ipp:169
#3 0x08052c68 in asio::io_service::run_one (this=0xbffff08c) at /src/cpp/external_lib/asio/include/asio/impl/io_service.ipp:71
#4 0x08051f32 in C_priority_task_queue::run (this=0xbffff094) at priority_task_queue.cpp:19
#5 0x08049ac3 in main () at main.cpp:46
And here there is the MakeFile:
TARGET=main
SOURCES= main.cpp base_timer.cpp priority_task_queue.cpp
SOURCE_DIR=.
INCLUDE_LIB= -L/src/cpp/libcore
INCLUDE_DIR=-I/src/cpp/external_lib/asio/include \
-I/src/cpp/libcore/include
INSTALL_DIR=.
LIB=-pthread
CXX=g++
CFLAGS=-Wall -fexceptions -fpermissive -std=c++11 -DASIO_STANDALONE
CFLAGS_DEBUG = -g3 -DDEBUG
OBJDIR_DEBUG=obj
BINDIR_DEBUG=.
OBJECTS_DEBUG:= $(addprefix $(OBJDIR_DEBUG)/,$(SOURCES:.cpp=.o))
all: debug
$(OBJDIR_DEBUG)/%.o: $(SOURCE_DIR)/%.cpp
#test -d $(OBJDIR_DEBUG) || mkdir -p $(OBJDIR_DEBUG)
$(CXX) $(CFLAGS) $(CFLAGS_DEBUG) $(INCLUDE_DIR) -c $< -o $#
debug: $(OBJECTS_DEBUG)
#test -d $(BINDIR_DEBUG) || mkdir -p $(BINDIR_DEBUG)
$(CXX) -o $(BINDIR_DEBUG)/$(TARGET) $^ $(INCLUDE_LIB) $(LIB)
UPDATE
I my investigation, I have found that if I define the base_timer members (basically asio::high_resolution_timer) initializations in the .h, the code runs ok, but if I do this in the .cpp, the code crash.
I mean,
explicit C_timer(C_priority_task_queue& prio_queue, size_t priority):
_timer(prio_queue.io()), _timer_id(0), _prio_queue(prio_queue), _priority(priority){}
in .h works, but
C_timer::C_timer(C_priority_task_queue& prio_queue, size_t priority):
_timer(prio_queue.io()), _timer_id(0), _prio_queue(prio_queue), _priority(priority){}
in .cpp fails
Except for "unnatural" juggling with chrono (timepoint or duration, pick one!) the code looks ok. I can't reproduce any failure (GCC, linux):
Live On Coliru
If adding random variables make problems appear/disappear, you should think of Undefined Behaviour, use static analysis, valgrind/purify/... and code scrutiny to find your culprit. Valgrind, ASAN and UBSAN ran clean on my PC
#sehe thanks for your effort. The diference is If I put every code into a single file, main.cpp, it runs, but if I separate into several files, the problem still there. In other hand, If I instanciate a high_resolution_timer object in the main.cpp, no matter the place (inside main(), in separate function that never is called, ...) it runs, but without it, a segmentation fault is raised.
That's great: you have found a potential source of the UB: look at the use of static variables or inline functions that are not ODR-safe. (Double check all translation units are using the same compiler flags).
Also, keep in mind UB is UNDEFINED, so like adding an unrelated _timer1 changes the apparent behaviour (without changing the source of UB) the same thing could make it appear to work.
The fact that it runs clean on my machine tells you that this would have to be a platform-specific source of UB
The problem was that I had been using the version 1.10.2 of the library and it seems there was a bug.
I have updated to the last version 1.10.6 and now it runs ok.

How can I avoid an exception thrown by <thread> in C++11?

I am trying to write multi-thread software using the thread library in C++11. Some basic tutorials found on the internet can compile and run as expected. But my own application separated into classes always throws an exception.
Could anyone kindly tell me which part of the code should be fixed, please?
$ clang++ -std=c++11 -stdlib=libc++ BaseInterface.cxx -c -o BaseInterface.o
$ clang++ -std=c++11 -stdlib=libc++ SocketReceiver.cxx -c -o SocketReceiver.o
$ clang++ -std=c++11 -stdlib=libc++ main.cxx -c -o main.o
$ clang++ -std=c++11 -stdlib=libc++ main.o BaseInterface.o SocketReceiver.o -o main
$ gdb main
(gdb) run
Starting program: /Users/oxon/test/main
Reading symbols for shared libraries ++............................ done
libc++abi.dylib: terminate called throwing an exception
Program received signal SIGABRT, Aborted.
[Switching to process 859 thread 0x40b]
0x00007fff88df8212 in __pthread_kill ()
(gdb) bt
#0 0x00007fff88df8212 in __pthread_kill ()
#1 0x00007fff8bc85af4 in pthread_kill ()
#2 0x00007fff8bcc9dce in abort ()
#3 0x00007fff894d3a17 in abort_message ()
#4 0x00007fff894d13c6 in default_terminate ()
#5 0x00007fff89874887 in _objc_terminate ()
#6 0x00007fff894d13f5 in safe_handler_caller ()
#7 0x00007fff894d1450 in std::terminate ()
#8 0x00007fff894d25b7 in __cxa_throw ()
#9 0x00007fff8a9ba3b9 in std::__1::thread::join ()
#10 0x0000000100000cf0 in SocketReceiver::Receive ()
#11 0x0000000100000c6d in SocketReceiver::DoReceive ()
#12 0x0000000100001593 in _ZNSt3__114__thread_proxyINS_5tupleIJPFPvS2_ES2_EEEEES2_S2_ ()
#13 0x00007fff8bc84742 in _pthread_start ()
#14 0x00007fff8bc71181 in thread_start ()
This is the result on OS X 10.8. Scientific Linux 6 with GCC 4.4 also gives a similar result.
= BaseInterface.h =
#ifndef BASE_INTERFACE_H
#define BASE_INTERFACE_H
#include "SocketReceiver.h"
class BaseInterface
{
private:
SocketReceiver* fReceiver;
public:
BaseInterface();
virtual ~BaseInterface();
virtual void Close();
virtual void Open();
;
#endif
= BaseInterface.cxx =
#include <iostream>
#include <string.h>
#include <unistd.h>
#include "BaseInterface.h"
BaseInterface::BaseInterface()
{
fReceiver = new SocketReceiver(this);
}
//______________________________________________________________________________
BaseInterface::~BaseInterface()
{
Close();
delete fReceiver;
fReceiver = 0;
}
//______________________________________________________________________________
void BaseInterface::Close()
{
fReceiver->Stop();
usleep(10000);
while(fReceiver->IsRunning()){
usleep(10000);
} // while
}
//______________________________________________________________________________
void BaseInterface::Open()
{
fReceiver->Start();
}
= SocketReceiver.h =
#ifndef SOCKET_RECEIVER_H
#define SOCKET_RECEIVER_H
#include <thread>
#include <mutex>
class BaseInterface;
class SocketReceiver
{
private:
BaseInterface* fInterface;
bool fIsRunning;
std::mutex fMutex;
bool fStop;
std::thread* fThread;
public:
SocketReceiver(BaseInterface* interface = 0);
virtual ~SocketReceiver();
bool IsRunning() const {return fThread ? true : false;}
static void* DoReceive(void* arg);
void Receive();
void Start();
void Stop();
};
#endif
= SocketReceiver.cxx =
#include <iostream>
#include <thread>
#include <unistd.h>
#include "BaseInterface.h"
#include "SocketReceiver.h"
SocketReceiver::SocketReceiver(BaseInterface* interface)
{
fInterface = interface;
fStop = true;
fThread = 0;
}
//______________________________________________________________________________
SocketReceiver::~SocketReceiver()
{
}
//______________________________________________________________________________
void* SocketReceiver::DoReceive(void* arg)
{
SocketReceiver* receiver = (SocketReceiver*)arg;
receiver->Receive();
return 0;
}
//______________________________________________________________________________
void SocketReceiver::Receive()
{
while(not fStop){
fMutex.lock();
usleep(10000);
fMutex.unlock();
} // while
fThread->join();
delete fThread;
fThread = 0;
}
//______________________________________________________________________________
void SocketReceiver::Start()
{
fStop = false;
fThread = new std::thread(DoReceive, (void*)this);
}
//______________________________________________________________________________
void SocketReceiver::Stop()
{
fStop = true;
}
= main.cxx =
#include "BaseInterface.h"
int main()
{
BaseInterface interface;
interface.Open();
interface.Close();
return 0;
}
You're joining the thread in itself. Call join in the parent thread, like in SocketReceiver::Stop.
When join is called, it cleans up underlying data. And if you call it in the thread you're running then that data will be removed while the thread still needs it.
If the function run by a std::thread exits via and exception then std::terminate will be called.
std::thread::join() is specified to throw std::system_error with an error code resource_deadlock_would_occur if join() is called in the same thread, i.e. a thread cannot join itself. So your attempt to make the thread join itself causes an exception which terminates the process. A thread cannot join itself, joining is defined as "wait for the thread to complete" so obviously cannot be done by the thread itself, it would block waiting for itself to finish, which can't happen until the call to join() finishes, which can't happen until the thread finishes, which can't happen until the call to join() finishes ... can you see where this is going?
Also why are you doing this?
fThread = new std::thread(DoReceive, (void*)this);
std::thread is not pthread_create, you don't need to pass it void*, just get rid of DoReceive and call:
fThread = new std::thread(&SocketReceiver::Receive, this);
And why is your std::thread allocated with new? That's not necessary either, you can use a std::thread member and use joinable() to check if it's active or not, instead of checking if the pointer is non-null.