Programming Forums

Programming Forums (http://www.programmingforums.org/forumindex.php)
-   C++ (http://www.programmingforums.org/forum15.html)
-   -   portable thread implementation problem (http://www.programmingforums.org/showthread.php?t=13547)

rwm Jul 13th, 2007 7:18 AM

portable thread implementation problem
 
Heya!

Im trying to create a portable thread library, as you can see this is just a test with POSIX threads...

Im confused as to why this is causing a seg fault...

:

#include <iostream>
using namespace std;

//POSIX threads
#include <pthread.h>
#include <semaphore.h>

class test {
        public:
                test() {
                        ::pthread_create(&_thread,0,0,0);
                }
                ~test() {
                        ::pthread_join(_thread,0);
                }
                void run() {
                        cout << "running thread" << endl;
                }
        private:
                //invalidate copy operations
                test(const test &);                //no impl
                test &operator=(const test &);        //no impl
                //data
                pthread_t _thread;
};

int main() {
        test _test;
        _test.run();
        //test::~test() causes seg fault

        return 0;
}


hope someone can help!

thanks!

:D

The Dark Jul 13th, 2007 7:45 AM

You need to pass a start_routine to pthread_create. Otherwise, the new thread won't know what to do.

rwm Jul 13th, 2007 7:57 AM

hey man! thanks for the reply!

ah thats why!

thanks for pointing that out :)

rwm Jul 16th, 2007 5:31 AM

heya!

i spent the whole weekend studying open source software - looking for a way to write a portable thread class. ive written a simple Thread class and well im having a problem understanding why this code is running like so:

:

#include <iostream>
using namespace std;

class Exception : public std::exception {
        ...
};

//-------------------------------------------------------------------//

class Thread {
        public:
                //constructor
                Thread();
                //destructor
                virtual ~Thread();
                //run thread
                void run();
        private:
                //prevent copy construction
                //we dont explicitly create
                //a new copy, just return "this"
                Thread(const Thread &other) {
                        *this = other;
                }
                Thread &operator=(const Thread &) {
                        return *this;
                }
                //start thread
                void start();
                //thread function
                static void *threadFunction(void *arg);
                //data
                pthread_t thread;
        protected:
                //threads execution task
                virtual void execute() = 0;
};

//-------------------------------------------------------------------//

Thread::Thread() {
        start();
}

Thread::~Thread() {
        if(pthread_join(thread,0) != 0)
                throw Exception("could not join thread",__FILE__,__LINE__);
}

void Thread::run() {
        execute();
}

void Thread::start() {
        if(pthread_create(&thread,0,&(Thread::threadFunction),this) != 0)
                throw Exception("could not create new thread",__FILE__,__LINE__);
}

void *Thread::threadFunction(void *arg) {
        Thread *thd = reinterpret_cast<Thread *>(arg);
        if(thd)
                thd->run();
        return (void *)0;
}

//-------------------------------------------------------------------//

class TestThread : public Thread {
        public:
                TestThread() : Thread() {}
                ~TestThread() {}
        protected:
                void execute() {
                        cout << "Executing Test thread..." << endl;
                        for(int i=0; i<5; i++) {
                                cout << "Test thread working..." << endl;
                                sleep(1);
                        }
                        cout << "Test thread terminating..." << endl;
                }
};

//-------------------------------------------------------------------//

int main() {
        //
        try {

                //
                TestThread tt;
                tt.run();

        } catch(Exception x) {
                cout << x << endl;
        }

        return 0;
}


this is the output

:

Executing Test thread...
Test thread working...
Executing Test thread...
Test thread working...
Test thread working...
Test thread working...
Test thread working...
Test thread working...
Test thread working...
Test thread working...
Test thread working...
Test thread working...
Test thread terminating...
Test thread terminating...


i dont understand why the thread is being executed twice???

hope someone can help! thanks!

:D

The Dark Jul 16th, 2007 8:37 AM

Your thread is being run through the threadFunction, but you are also calling run() again in the main(). Take out the tt.run(); call in your main().
I'd recommend that you change the way your thread class works so that it doesn't autostart. Otherwise you cant create a few different threads objects and control when they start.

rwm Jul 16th, 2007 9:30 AM

heya!

thanks for the reply! ok, i already tried that, didnt work, i guess this is what you meant?

ive changed it, so the thread doesnt autostart - all i have to do is call the start() method and the thread will begin executing:

:

#include <iostream>
using namespace std;

class Exception : public std::exception {
        public:
                Exception() {}
                Exception(std::string s) : str(s) {}
                virtual ~Exception() throw() {}
                friend ostream &operator<<(ostream &stream,const Exception &src) {
                        return stream << src.str << endl;
                }
        private:
                std::string str;
};

//-------------------------------------------------------------------//

class Thread {
        public:
                Thread() {}
                virtual ~Thread();
                void start();
        private:
                static void *threadFunction(void *arg);
                pthread_t thread;
        protected:
                virtual void run() = 0;
};

//-------------------------------------------------------------------//

Thread::~Thread() {
        if(pthread_join(thread,0) != 0)
                throw Exception("could not join thread");
}

void Thread::start() {
        if(pthread_create(&thread,0,&(Thread::threadFunction),this) != 0)
                throw Exception("could not create new thread");
}

void *Thread::threadFunction(void *arg) {
        Thread *thd = reinterpret_cast<Thread *>(arg);
        if(thd)
                thd->run();
        return (void *)0;
}

//-------------------------------------------------------------------//

class TestThread : public Thread {
        public:
                TestThread() : Thread() {}
                ~TestThread() {}
        protected:
                void run() {
                        cout << "Running Test thread..." << endl;
                        for(int i=0; i<5; i++) {
                                cout << "Test thread working..." << endl;
                                sleep(1);
                        }
                        cout << "Test thread terminating..." << endl;
                }
};

//-------------------------------------------------------------------//

int main() {
        //
        try {

                //
                TestThread tt;
                tt.start();

        } catch(Exception x) {
                cout << x << endl;
        }

        return 0;
}


i get this:

:

pure virtual method called
terminate called without an active exception
Aborted (core dumped)


hope you can help! thanks! :)

The Dark Jul 16th, 2007 9:44 PM

The problem is that your tt variable is going out of scope before the thread has time to work. Even though you have the pthread_join in the destructor of Thread, I think by that by the time the inner destructor is called, the virtual function pointers have been removed.

You can test this by getting some keyboard input after the "start" call. The thread then works. This is probably why your first version worked (twice) the thread had a chance to start before the object went out of scope.

Also note that you should initialise "thread" to 0 in the constructor, just in case somebody creates a Thread object but doesn't call start.

You could add a "WaitForExit" function and call it in your derived class destructor, but that makes it a bit less convenient to use.

I think because threading is run concurrently, it doesn't lend itself well to objects you can create on the stack, as they will get destroyed when they fall out of scope, even if the thread is still running. At work we use a reference counter approach, so that the object is only destroyed once the thread is finished and the calling function has indicated it is finished as well.

lectricpharaoh Jul 17th, 2007 1:07 AM

Another approach you could try is to make the constructor(s) private, and have static 'factory methods' to create instances. These instances could create the objects on the heap, so you wouldn't have problems with them being destructed (yes, desctructed) prematurely. You'd still need to make sure you don't lose the reference before the thread gets stopped and the object gets released, or you'll have a memory leak, but there are ways to encapsulate much of this fucntionality as well.

rwm Jul 17th, 2007 3:44 AM

hey guys!

thanks for the replies! oh ok, that makes sense! mmm...

i guess reference counting could work, but thats a little inconvenient... or i could try adding a conditional in my start() method but again thats a hassle...

do you have any links to any tutorials/open source that you reccomend? ive been googling a while and found a couple, but both work the same way (using conditionals)

thanks guys! :)

rwm Jul 17th, 2007 10:59 AM

hey dont worry guys, ive fixed it!

thanks for the help! :D


All times are GMT -5. The time now is 2:49 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC