Data race? segfault, but where is the issue? - c++

There following simple program crashes occasionally, but I don't understand what can be worong with it?
It's compiled with '-pthread -std=c++11 -g -O2 -pie -fpie -std=c++11'
valgrind drd reports a data race, but I can't see why.
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
bool running;
pthread_rwlock_t _rwlock;
class Dummy {
public:
Dummy() : _refs(0) {
Ref();
}
volatile int _refs;
void Ref() {
++_refs;
}
void Unref() {
--_refs;
if (_refs <= 0) {
delete this;
}
}
};
static Dummy* s_dummy;
Dummy* get_dummy() {
pthread_rwlock_rdlock(&_rwlock);
Dummy* ret = s_dummy;
ret->Ref();
pthread_rwlock_unlock(&_rwlock);
return ret;
}
void *work1(void*) {
while (running) {
Dummy* new_dummy = new Dummy();
pthread_rwlock_wrlock(&_rwlock);
Dummy* to_del = s_dummy;
s_dummy = new_dummy;
pthread_rwlock_unlock(&_rwlock);
to_del->Unref();
}
}
void *work2(void*) {
while (running) {
Dummy* p = get_dummy();
p->Unref();
}
}
int main() {
running = true;
pthread_rwlock_init(&_rwlock, NULL);
s_dummy = new Dummy();
pthread_t threads[2];
threads[0] = pthread_create(&threads[0], NULL, work1, NULL);
threads[0] = pthread_create(&threads[1], NULL, work2, NULL);
sleep(30);
running = false;
void* ret;
for (int i = 0; i < 2; ++i) {
pthread_join(threads[i], &ret);
}
return 0;
}

I can't speak for the exact message you're getting since you didn't add it, however you at least have a data race on _refs and it may cause a double delete.
As an example, both threads can be inside Unref on the same object at the same time with _refs initially == 2.
Let's say both threads run --_refs, the value of _refs will then be 0. Then both threads check if refs is zero, and since _refs is volatile they both read the value 0 from memory and both delete.
What you probably want for _refs is an atomic variable, not a volatile.

The two unrefs in work1 and work2 can conflict. There is nothing stopping a delete from happening in both threads simultaneously.
Also, you should make running volatile, or better yet, atomic.
Finally, it seems an aweful lot of work for something that could trivially be solved using a shared_ptr. The code below is equivalent to yours:
#include <atomic>
#include <memory>
#include <thread>
class Dummy {
};
std::atomic<bool> running = true;
static std::shared_ptr<Dummy> s_dummy = std::make_shared<Dummy> ();
void work1 () {
while (running)
s_dummy = std::make_shared<Dummy> ();
}
void work2 () {
while (running)
s_dummy = nullptr;
}
int main() {
std::thread t1 (work1);
std::thread t2 (work2);
sleep (30);
running = false;
t1.join ();
t2.join ();
return 0;
}

Related

Atomically incrementing an integer in shared memory for multiple processes on linux x86-64 with gcc

The Question
What's a good way to increment a counter and signal once that counter reaches a given value (i.e., signaling a function waiting on blocks until full, below)? It's a lot like asking for a semaphore. The involved processes are communicating via shared memory (/dev/shm), and I'm currently trying to avoid using a library (like Boost).
Initial Solution
Declare a struct that contains a SignalingIncrementingCounter. This struct is allocated in shared memory, and a single process sets up the shared memory with this struct before the other processes begin. The SignalingIncrementingCounter contains the following three fields:
A plain old int to represent the counter's value.
Note: Due to the MESI caching protocol, we are guaranteed that if one cpu core modifies the value, that the updated value will be reflected in other caches once the value is read from those other caches.
A pthread mutex to guard the reading and incrementing of the integer counter
A pthread condition variable to signal when the integer has reached a desirable value
Other Solutions
Instead of using an int, I also tried using std::atomic<int>. I've tried just defining this field as a member of the SignalingIncrementingCounter class, and I've also tried allocating it into the struct at run time with placement new. It seems that neither worked better than the int.
The following should work.
The Implementation
I include most of the code, but I leave out parts of it for the sake of brevity.
signaling_incrementing_counter.h
#include <atomic>
struct SignalingIncrementingCounter {
public:
void init(const int upper_limit_);
void reset_to_empty();
void increment(); // only valid when counting up
void block_until_full(const char * comment = {""});
private:
int upper_limit;
volatile int value;
pthread_mutex_t mutex;
pthread_cond_t cv;
};
signaling_incrementing_counter.cpp
#include <pthread.h>
#include <stdexcept>
#include "signaling_incrementing_counter.h"
void SignalingIncrementingCounter::init(const int upper_limit_) {
upper_limit = upper_limit_;
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
int retval = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
if (retval) {
throw std::runtime_error("Error while setting sharedp field for mutex");
}
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&mutex, &attr);
pthread_mutexattr_destroy(&attr);
}
{
pthread_condattr_t attr;
pthread_condattr_init(&attr);
pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&cv, &attr);
pthread_condattr_destroy(&attr);
}
value = 0;
}
void SignalingIncrementingCounter::reset_to_empty() {
pthread_mutex_lock(&mutex);
value = 0;
// No need to signal, because in my use-case, there is no function that unblocks when the value changes to 0
pthread_mutex_unlock(&mutex);
}
void SignalingIncrementingCounter::increment() {
pthread_mutex_lock(&mutex);
fprintf(stderr, "incrementing\n");
++value;
if (value >= upper_limit) {
pthread_cond_broadcast(&cv);
}
pthread_mutex_unlock(&mutex);
}
void SignalingIncrementingCounter::block_until_full(const char * comment) {
struct timespec max_wait = {0, 0};
pthread_mutex_lock(&mutex);
while (value < upper_limit) {
int val = value;
printf("blocking until full, value is %i, for %s\n", val, comment);
clock_gettime(CLOCK_REALTIME, &max_wait);
max_wait.tv_sec += 5; // wait 5 seconds
const int timed_wait_rv = pthread_cond_timedwait(&cv, &mutex, &max_wait);
if (timed_wait_rv)
{
switch(timed_wait_rv) {
case ETIMEDOUT:
break;
default:
throw std::runtime_error("Unexpected error encountered. Investigate.");
}
}
}
pthread_mutex_unlock(&mutex);
}
Using either an int or std::atomic works.
One of the great things about the std::atomic interface is that it plays quite nicely with the int "interface". So, the code is almost exactly the same. One can switch between each implementation below by adding a #define USE_INT_IN_SHARED_MEMORY_FOR_SIGNALING_COUNTER true.
I'm not so sure about statically creating the std::atomic in shared memory, so I use placement new to allocate it. My guess is that relying on the static allocation would work, but it may technically be undefined behavior. Figuring that out is beyond the scope of my question, but a comment on that topic would be quite welcome.
signaling_incrementing_counter.h
#include <atomic>
#include "gpu_base_constants.h"
struct SignalingIncrementingCounter {
public:
/**
* We will either count up or count down to the given limit. Once the limit is reached, whatever is waiting on this counter will be signaled and allowed to proceed.
*/
void init(const int upper_limit_);
void reset_to_empty();
void increment(); // only valid when counting up
void block_until_full(const char * comment = {""});
// We don't have a use-case for the block_until_non_full
private:
int upper_limit;
#if USE_INT_IN_SHARED_MEMORY_FOR_SIGNALING_COUNTER
volatile int value;
#else // USE_INT_IN_SHARED_MEMORY_FOR_SIGNALING_COUNTER
std::atomic<int> value;
std::atomic<int> * value_ptr;
#endif // USE_INT_IN_SHARED_MEMORY_FOR_SIGNALING_COUNTER
pthread_mutex_t mutex;
pthread_cond_t cv;
};
signaling_incrementing_counter.cpp
#include <pthread.h>
#include <stdexcept>
#include "signaling_incrementing_counter.h"
void SignalingIncrementingCounter::init(const int upper_limit_) {
upper_limit = upper_limit_;
#if !GPU_USE_INT_IN_SHARED_MEMORY_FOR_SIGNALING_COUNTER
value_ptr = new(&value) std::atomic<int>(0);
#endif // GPU_USE_INT_IN_SHARED_MEMORY_FOR_SIGNALING_COUNTER
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
int retval = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
if (retval) {
throw std::runtime_error("Error while setting sharedp field for mutex");
}
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&mutex, &attr);
pthread_mutexattr_destroy(&attr);
}
{
pthread_condattr_t attr;
pthread_condattr_init(&attr);
pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&cv, &attr);
pthread_condattr_destroy(&attr);
}
reset_to_empty(); // should be done at end, since mutex functions are called
}
void SignalingIncrementingCounter::reset_to_empty() {
int mutex_rv = pthread_mutex_lock(&mutex);
if (mutex_rv) {
throw std::runtime_error("Unexpected error encountered while grabbing lock. Investigate.");
}
value = 0;
// No need to signal, because there is no function that unblocks when the value changes to 0
pthread_mutex_unlock(&mutex);
}
void SignalingIncrementingCounter::increment() {
fprintf(stderr, "incrementing\n");
int mutex_rv = pthread_mutex_lock(&mutex);
if (mutex_rv) {
throw std::runtime_error("Unexpected error encountered while grabbing lock. Investigate.");
}
++value;
fprintf(stderr, "incremented\n");
if (value >= upper_limit) {
pthread_cond_broadcast(&cv);
}
pthread_mutex_unlock(&mutex);
}
void SignalingIncrementingCounter::block_until_full(const char * comment) {
struct timespec max_wait = {0, 0};
int mutex_rv = pthread_mutex_lock(&mutex);
if (mutex_rv) {
throw std::runtime_error("Unexpected error encountered while grabbing lock. Investigate.");
}
while (value < upper_limit) {
int val = value;
printf("blocking during increment until full, value is %i, for %s\n", val, comment);
/*const int gettime_rv =*/ clock_gettime(CLOCK_REALTIME, &max_wait);
max_wait.tv_sec += 5;
const int timed_wait_rv = pthread_cond_timedwait(&cv, &mutex, &max_wait);
if (timed_wait_rv)
{
switch(timed_wait_rv) {
case ETIMEDOUT:
break;
default:
pthread_mutex_unlock(&mutex);
throw std::runtime_error("Unexpected error encountered. Investigate.");
}
}
}
pthread_mutex_unlock(&mutex);
}

How to suspend and resume a POSIX thread in C++?

As I came to know creating and terminating thread abruptly
using pthread_kill() everytime is not a good way to do, so I am going
with suspend and resume method for a thread using thread1.suspend() and
thread1.resume(), whenever needed. How to do/implement this?
Take below LED blinking code for reference. During thread1.start() creating thread with suspended = false; is continuing as it is stuck in a while loop.
Calling thread1.suspend() has no effect.
#define on 1
#define off 0
void gpio_write(int fd, int value);
void* led_Flash(void* args);
class PThread {
public:
pthread_t threadID;
bool suspended;
int fd;
pthread_mutex_t m_SuspendMutex;
pthread_cond_t m_ResumeCond;
void start() {
suspended = false;
pthread_create(&threadID, NULL, led_Flash, (void*)this );
}
PThread(int fd1) { this->fd=fd1; }
~PThread() { }
void suspend() {
pthread_mutex_lock(&m_SuspendMutex);
suspended = true;
printf("suspended\n");
do {
pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
} while (suspended);
pthread_mutex_unlock(&m_SuspendMutex);
}
void resume() {
/* The shared state 'suspended' must be updated with the mutex held. */
pthread_mutex_lock(&m_SuspendMutex);
suspended = false;
printf("Resumed\n");
pthread_cond_signal(&m_ResumeCond);
pthread_mutex_unlock(&m_SuspendMutex);
}
};
void* led_Flash(void* args)
{
PThread* pt= (PThread*) args;
int ret=0;
int fd= pt->fd;
while(pt->suspended == false)
{
gpio_write(fd,on);
usleep(1);
gpio_write(fd,off);
usleep(1);
}
return NULL;
}
int main()
{
int fd1=1,fd2=2, fd3=3;
class PThread redLED(fd1);
class PThread amberLED(fd2);
class PThread greenLED(fd3);
redLED.start();
amberLED.start();
greenLED.start();
sleep(1);
redLED.suspend();
return 0;
}
Could some body help me, please?
After a little modification of above code , it seems working . Thanks guy for pointing out issues on above code, the changes are as follow.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<iostream>
#define on 1
#define off 0
void gpio_write(int fd, int value);
void* led_Flash(void* args);
class PThread {
public:
pthread_t threadID;
volatile int suspended;
int fd;
pthread_mutex_t lock;
PThread(int fd1)
{
this->fd=fd1;
this->suspended =1; //Initial state: suspend blinking untill resume call
pthread_mutex_init(&this->lock,NULL);
pthread_create(&this->threadID, NULL, led_Flash, (void*)this );
}
~PThread()
{
pthread_join(this->threadID , NULL);
pthread_mutex_destroy(&this->lock);
}
void suspendBlink() {
pthread_mutex_lock(&this->lock);
this->suspended = 1;
pthread_mutex_unlock(&this->lock);
}
void resumeBlink() {
pthread_mutex_lock(&this->lock);
this->suspended = 0;
pthread_mutex_unlock(&this->lock);
}
};
void gpio_write(int fd, int value)
{
if(value!=0)
printf("%d: on\n", fd);
else
printf("%d: off\n", fd);
}
void* led_Flash(void* args)
{
PThread* pt= (PThread*) args;
int fd= pt->fd;
while(1)
{
if(!(pt->suspended))
{
gpio_write(fd,on);
usleep(1);
gpio_write(fd,off);
usleep(1);
}
}
return NULL;
}
int main()
{
//Create threads with Initial state: suspend/stop blinking untill resume call
class PThread redLED(1);
class PThread amberLED(2);
class PThread greenLED(3);
// Start blinking
redLED.resumeBlink();
amberLED.resumeBlink();
greenLED.resumeBlink();
sleep(5);
// suspend/stop blinking
amberLED.suspendBlink();
sleep(5);
redLED.suspendBlink();
sleep(5);
amberLED.suspendBlink();
sleep(5);
redLED.resumeBlink();
pthread_exit(NULL);
return 0;
}

C++11 Threads Not Joining

I have experience with threads in Java but want to learn how to use them in C++11. I tried to make a simple threadpool, where threads are created once and can be asked to execute tasks.
#include <thread>
#include <iostream>
#define NUM_THREADS 2
class Worker
{
public:
Worker(): m_running(false), m_hasData(false)
{
};
~Worker() {};
void execute()
{
m_running = true;
while(m_running)
{
if(m_hasData)
{
m_system();
}
m_hasData = false;
}
};
void stop()
{
m_running = false;
};
void setSystem(const std::function<void()>& system)
{
m_system = system;
m_hasData = true;
};
bool isIdle() const
{
return !m_hasData;
};
private:
bool m_running;
std::function<void()> m_system;
bool m_hasData;
};
class ThreadPool
{
public:
ThreadPool()
{
for(int i = 0; i < NUM_THREADS; ++i)
{
m_threads[i] = std::thread(&Worker::execute, &m_workers[i]);
}
};
~ThreadPool()
{
for(int i = 0; i < NUM_THREADS; ++i)
{
std::cout << "Stopping " << i << std::endl;
m_workers[i].stop();
m_threads[i].join();
}
};
void execute(const std::function<void()>& system)
{
// Finds the first non-idle worker - not really great but just for testing
for(int i = 0; i < NUM_THREADS; ++i)
{
if(m_workers[i].isIdle())
{
m_workers[i].setSystem(system);
return;
}
}
};
private:
Worker m_workers[NUM_THREADS];
std::thread m_threads[NUM_THREADS];
};
void print(void* in, void* out)
{
char** in_c = (char**)in;
printf("%s\n", *in_c);
}
int main(int argc, const char * argv[]) {
ThreadPool pool;
const char* test_c = "hello_world";
pool.execute([&]() { print(&test_c, nullptr); });
}
The output of this is:
hello_world
Stopping 0
After that, the main thread halts, because it's waiting for the first thread to join (in the destructor of the ThreadPool). For some reason, the m_running variable of the workers is not set to false, which keeps the application running indefinitely.
In Worker::stop the member m_running is written in the main thread, while it is read in execute in a different thread. This is undefined behavior. You need to protect read/write access from different threads. In this case I would recommend using std::atomic<bool> for m_running.
Edit: the same holds for m_hasData.

Embedding matplotlib in C++

I am reading a message from a socket with C++ code and am trying to plot it interactively with matplotlib, but it seems Python code will block the main thread, no matter I use show() or ion() and draw(). ion() and draw() won't block in Python.
Any idea how to plot interactively with matplotlib in C++ code?
An example would be really good.
Thanks a lot.
You may also try creating a new thread that does the call to the
blocking function, so that it does not block IO in your main program
loop. Use an array of thread objects and loop through to find an unused
one, create a thread to do the blocking calls, and have another thread
that joins them when they are completed.
This code is a quick slap-together I did to demonstrate what I mean about
using threads to get pseudo asynchronous behavior for blocking functions...
I have not compiled it or combed over it very well, it is simply to show
you how to accomplish this.
#include <pthread.h>
#include <sys/types.h>
#include <string>
#include <memory.h>
#include <malloc.h>
#define MAX_THREADS 256 // Make this as low as possible!
using namespace std;
pthread_t PTHREAD_NULL;
typedef string someTypeOrStruct;
class MyClass
{
typedef struct
{
int id;
MyClass *obj;
someTypeOrStruct input;
} thread_data;
void draw(); //Undefined in this example
bool getInput(someTypeOrStruct *); //Undefined in this example
int AsyncDraw(MyClass * obj, someTypeOrStruct &input);
static void * Joiner(MyClass * obj);
static void * DoDraw(thread_data *arg);
pthread_t thread[MAX_THREADS], JoinThread;
bool threadRunning[MAX_THREADS], StopJoinThread;
bool exitRequested;
public:
void Main();
};
bool MyClass::getInput(someTypeOrStruct *input)
{
}
void MyClass::Main()
{
exitRequested = false;
pthread_create( &JoinThread, NULL, (void *(*)(void *))MyClass::Joiner, this);
while(!exitRequested)
{
someTypeOrStruct tmpinput;
if(getInput(&tmpinput))
AsyncDraw(this, tmpinput);
}
if(JoinThread != PTHREAD_NULL)
{
StopJoinThread = true;
pthread_join(JoinThread, NULL);
}
}
void *MyClass::DoDraw(thread_data *arg)
{
if(arg == NULL) return NULL;
thread_data *data = (thread_data *) arg;
data->obj->threadRunning[data->id] = true;
// -> Do your draw here <- //
free(arg);
data->obj->threadRunning[data->id] = false; // Let the joinThread know we are done with this handle...
}
int MyClass::AsyncDraw(MyClass *obj, someTypeOrStruct &input)
{
int timeout = 10; // Adjust higher to make it try harder...
while(timeout)
{
for(int i = 0; i < MAX_THREADS; i++)
{
if(thread[i] == PTHREAD_NULL)
{
thread_data *data = (thread_data *)malloc(sizeof(thread_data));
if(data)
{
data->id = i;
data->obj = this;
data->input = input;
pthread_create( &(thread[i]), NULL,(void* (*)(void*))MyClass::DoDraw, (void *)&data);
return 1;
}
return 0;
}
}
timeout--;
}
}
void *MyClass::Joiner(MyClass * obj)
{
obj->StopJoinThread = false;
while(!obj->StopJoinThread)
{
for(int i = 0; i < MAX_THREADS; i++)
if(!obj->threadRunning[i] && obj->thread[i] != PTHREAD_NULL)
{
pthread_join(obj->thread[i], NULL);
obj->thread[i] = PTHREAD_NULL;
}
}
}
int main(int argc, char **argv)
{
MyClass base;
base.Main();
return 0;
}
This way you can continue accepting input while the draw is occurring.
~~Fixed so the above code actually compiles, make sure to add -lpthread

Inner class and initialisation

I have a class defined like this: This is not all complete and probably won't compile.
class Server
{
public:
Server();
~Server();
class Worker
{
public:
Worker(Server& server) : _server(server) { }
~Worker() { }
void Run() { }
void Stop() { }
private:
Server& _server;
}
void Run()
{
while(true) {
// do work
}
}
void Stop()
{
// How do I stop the thread?
}
private:
std::vector<Worker> _workers;
};
My question is, how do I initialize the workers array passing in the outer class named Server.
What I want is a vector of worker threads. Each worker thread has it's own state but can access some other shared data (not shown). Also, how do I create the threads. Should they be created when the class object is first created or externally from a thread_group.
Also, how do I go about shutting down the threads cleanly and safely?
EDIT:
It seems that I can initialize Worker like this:
Server::Server(int thread_count)
: _workers(thread_count), Worker(*this)), _thread_count(thread_count) { }
And I'm currently doing this in Server::Run to create the threads.
boost::thread_group _threads; // a Server member variable
Server::Run(){
for (int i = 0; i < _thread_count; i++)
_threads.create_thread(boost::bind(&Server::Worker::Run, _workers(i)));
// main thread.
while(1) {
// Do stuff
}
_threads.join_all();
}
Does anyone see any problems with this?
And how about safe shutdown?
EDIT:
One problem I have found with it is that the Worker objects don't seem to get constructed!
oops. Yes they do I need a copy constructor on the Worker class.
But oddly, creating the threads results in the copy constructor for Worker being called multiple times.
I have done it with pure WINAPI, look:
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <vector>
using namespace std;
class Server
{
public:
class Worker
{
int m_id;
DWORD m_threadId;
HANDLE m_threadHandle;
bool m_active;
friend Server;
public:
Worker (int id)
{
m_id = id;
m_threadId = 0;
m_threadHandle = 0;
m_active = true;
}
static DWORD WINAPI Run (LPVOID lpParam)
{
Worker* p = (Worker*) lpParam; // it's needed because of the static modifier
while (p->m_active)
{
printf ("I'm a thread #%i\n", p->m_id);
Sleep (1000);
}
return 0;
}
void Stop ()
{
m_active = false;
}
};
Server ()
{
m_workers = new vector <Worker*> ();
m_count = 0;
}
~Server ()
{
delete m_workers;
}
void Run ()
{
puts ("Server is run");
}
void Stop ()
{
while (m_count > 0)
RemoveWorker ();
puts ("Server has been stopped");
}
void AddWorker ()
{
HANDLE h;
DWORD threadId;
Worker* n = new Worker (m_count ++);
m_workers->push_back (n);
h = CreateThread (NULL, 0, Worker::Run, (VOID*) n, CREATE_SUSPENDED, &threadId);
n->m_threadHandle = h;
n->m_threadId = threadId;
ResumeThread (h);
}
void RemoveWorker ()
{
HANDLE h;
DWORD threadId;
if (m_count <= 0)
return;
Worker* n = m_workers->at (m_count - 1);
m_workers->pop_back ();
n->Stop ();
TerminateThread (n->m_threadHandle, 0);
m_count --;
delete n;
}
private:
int m_count;
vector <Worker*>* m_workers;
};
int main (void)
{
Server a;
int com = 1;
a.Run ();
while (com)
{
if (kbhit ())
{
switch (getch ())
{
case 27: // escape key code
com = 0;
break;
case 'a': // add worker
a.AddWorker ();
break;
case 'r': // remove worker
a.RemoveWorker ();
break;
}
}
}
a.Stop ();
return 0;
}
There are no synchronization code here, because I haven't enougth time to do it... But I wish it will help you =)
Have you looked at boost asio at all? It looks like it could be a good fit for what you are trying to do. Additionally you can call boost asio's io_service's run (similar to your Run method) from many threads i.e. you can process your IO in many threads. Also of interest could be http://think-async.com/Asio/Recipes for an asio based thread-pool.
Have a look at the asio examples. Perhaps they offer an alternative way of handling what you are trying to do. Esp. have a look at how a clean shutdown is accomplished.