Thread init problem

Have a SDL_Thread *id1 as a public member of the class cLevel and create thread in Inti() method of the cLevel:

Code:

cLevel::Init()
{

char *tnames[1] = { “Thread 1” }; //names of threads
id1 = SDL_CreateThread ( runner, tnames[0] );

}

I end up with compile error:

Code:

cannot convert int (cLevel::)(void) to int ()(void) for argument 1 to SDL_Thread* SDL_CreateThread(int ()(void), void*)

runner is public member of the class cLevel also (int runner (void* data):wink:

I am just learning how to do this, would appreciate some help.

You cannot use member function pointers as function pointers. Member
function pointers are strange beasts, they are frequently bigger than
sizeof(void *). Read this for more information:
http://www.parashift.com/c++-faq-lite/pointers-to-members.html

The classic C++ way to do this is to use the void pointer to user data to
pass the “this” pointer to a static helper function, then have that function
invoke the member function you want:

class Worker
{
public:
Worker(/* … */);
virtual ~Worker() {}
virtual void run() = 0;
private:
// …
};

void threadHelper(void *ptr)
{
Worker *worker = static_cast<Worker *>(ptr);
worker->run();
}

void startThread(Worker *worker)
{
SDL_CreateThread(&threadHelper, worker);
}

The implementation of threadHelper() can be enclosed in a anonymous
namespace in a source file, preventing it from being incorrectly invoked on
the wrong type. Stuff that wants to run can then be derived from Worker. Any
data needed (like the name you are using here) can be included as member
variables of the derived class.

It is possible to do this in a more adhoc manner, but you need to be careful
of the types or else you could risk serious memory corruption. This is an
extremely simple form of something like boost::thread, which is going to be
included in C++0x. I’ve used something similar to the above before and it
worked quite well, except that the old version of GCC I was using ran into
trouble when dealing with exceptions in threads.On 29 August 2010 15:14, dekyco wrote:

runner is public member of the class cLevel also (int runner (void* data)[image:
Wink]

I am just learning how to do this, would appreciate some help.

Ok,thank you for reply.
As I know SDL_CreateThread returns a SDL_Thread? Do I need to have SDL_Thread pointer defined as a public/private
member of cLevel class?

Here is what I did:

Code:

namespace helper
{
void threadHelper(void *ptr)
{
MojThread *mojThread = static_cast<MojThread *>(ptr);
mojThread->Radi();
}
}

this is in level.cpp file.

void startThread(Worker *worker) is a cLevel public member like this:

Code:

void cLevel::startThread(MyThread *thread)
{
t = SDL_CreateThread(helper::threadHelper, thread);
}

I have made a MyThread class inherited from abstract Worker class.

Got an compile error:

Code:

In member function void cLevel::startThread(MyThread*):|
error: invalid conversion from void ()(void) to int ()(void)|
error: initializing argument 1 of SDL_Thread* SDL_CreateThread(int ()(void), void*)|
||=== Build finished: 2 errors, 0 warnings ===|

dekyco

Ok,thank you for reply.
As I know SDL_CreateThread returns a SDL_Thread? Do I need to have
SDL_Thread pointer defined as a public/private
member of cLevel class?

Here is what I did:

Code:

namespace helper
{
void threadHelper(void *ptr)
{
MojThread *mojThread = static_cast(ptr);
mojThread->Radi();
}
}

this is in level.cpp file.

void startThread(Worker *worker) is a cLevel public member like this:

Code:

void cLevel::startThread(MyThread *thread)
{
t = SDL_CreateThread(helper::threadHelper, thread);
}

I have made a MyThread class inherited from abstract Worker class.

Got an compile error:

Code:

In member function ?void cLevel::startThread(MyThread*)?:expressionless:
error: invalid conversion from ?void ()(void)? to ?int ()(void)?|
error: initializing argument 1 of ?SDL_Thread* SDL_CreateThread(int
()(void), void*)?|
||=== Build finished: 2 errors, 0 warnings ===|

It appears that if void threadHelper(void )
were instead int threadHelper(void )
it would fit the required signature for parameter 1 of
SDL_Thread
SDL_CreateThread(int (
)(void*), void*)On 8/29/2010 1:37 PM, dekyco wrote:

dekyco


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

That is correct,now compiles fine…
I am not sure how to actually start a thread now? It is supposed to be done in cLevel::Init() method.

I am confused with what parameters I need to call startThread(MyThread *thread) in the Init()
and in which way ( this->startThread(MyThread *thread), cLevel::startThread(MyThread *thread) …)

OK back to basics - have a look at this C implementation sample:
http://www.libsdl.org/intro.en/usingthreads.html

As you can see, SDL_CreateThread receives two things:

  • a pointer to a service function (the code that is being executed in
    the thread)
  • a pointer to the data passed to the service function (use is
    obligatory, but it is commonly used to pass pointers to a mutex or
    object instances in OOP)

To satisfy the first parameter requirements, one needs to implement a
function/method with the correct signature of “int f(void *)” as in
int threadHelper(void *ptr) { … }

To satisfy the second parameter requirement, pass any pointer such as
the instance of your Worker class and cast to (void *) as in
SDL_CreateThread(&threadHelper, (void *)worker);

The SDL_CreateThread starts to execute “threadHelper” immediately and
returns a handle that allows one to control execution flow (i.e. wait
for the thread to terminate, etc.). It would generally be managed by the
"parent" of the thread(s) and can be used also to collect the return
parameter from the service function with SDL_WaitThread async after the
thread execution has completed.

Hope that helps.On 8/29/10 7:14 AM, dekyco wrote:

Have a SDL_Thread *id1 as a public member of the class cLevel and
create thread in Inti() method of the cLevel:

Code:

cLevel::Init()
{

char *tnames[1] = { “Thread 1” }; //names of threads
id1 = SDL_CreateThread ( runner, tnames[0] );

}

I end up with compile error:

Code:

cannot convert ‘int (cLevel::)(void)’ to ‘int ()(void)’ for
argument ‘1’ to ‘SDL_Thread* SDL_CreateThread(int ()(void), void*)’

runner is public member of the class cLevel also (int runner (void*
data)Wink

I am just learning how to do this, would appreciate some help.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Ok thank you for reply Andreas.
This is how I did it: ‘MyThread* thread1;’ is a public member of cLevel class
cLevel::startThread(MyThread *thread) is a member of cLevel class, it has to start thread in the Init method
of this class by taking a thread1 pointer as parameter,like this:

Code:

cLevel:Init()
{

startThread(thread1);

}

this compiles as it should,but debugging in gdb gives this error:

Code:

cLevel Init
[New Thread 0xb6c42b90 (LWP 25653)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb6c42b90 (LWP 25653)]
0x080537e3 in helper::threadHelper (ptr=0x0) at level.cpp:160
160 myThread->Run();
(gdb)

That Run() method only contains ‘cout << “I am a thread.” << endl;’, i.e. it prints a string on stout.

dekyco

Your Thread pointer is uninitialised. Attempting to call the run() member
function on it will typically result in a segfault. You can either
dynamically allocate the Thread object and pass it to the startThread
function.

It would be simpler to have the thread as a member by value. Then you can
pass &thread, something like this:

// Header file
class Level {
public:
void Init();
private:
Thread thread;
SDL_Thread *threadHandle;
};

// Source file
void Level::Init()
{
threadHandle = startThread(&thread);
// Error checking if startThread() fails…
}

However given the amount of difficulty this is causing you so far leads me
to doubt you have the experience required to write working multi-threaded
code in C++. What is your thread doing? I suspect there might be an easier
way of doing this that simulates asynchronous behaviour without spawning an
operating system thread. Such an approach is far more likely to work for
you, threads are hard - even an experienced programmer can write
multi-threaded code that appears to work but contains race conditions and
mutual exclusion errors.On 31 August 2010 11:21, dekyco wrote:

Ok thank you for reply Andreas.
This is how I did it: ‘MyThread* thread1;’ is a public member of cLevel
class
cLevel::startThread(MyThread *thread) is a member of cLevel class, it has
to start thread in the Init method
of this class by taking a thread1 pointer as parameter,like this:

This is working, at least the program is not segfaulting.It is starting and immediatly exits when called
by Init():

Code:

[New Thread 0xb6c42b90 (LWP 27268)]
I am in the thread.
[Thread 0xb6c42b90 (LWP 27268) exited]

When started with a click on some gui element it runs independently from the rest of the program,
so I can move window,change gui ‘levels’,click other buttons etc without blocking (for now).

Thread is opening a pipe (popen) for another program and the output of this is displayed with SDL - so I am using SDL
as a gui frontend for command line.The goal is to have a non-blocking gui frontend for command line program.
So far command line is displaying its output and SDL is not blocking during this time but who knows…maybe
I am at least on the right track with this.

You are wright I do not have expirience with this at all…

Is SDL_WaitThread(thread, NULL) some sort of ‘pause’ for thread?

dekyco

WaitThread() instructs the calling thread to wait until the specified thread
finishes.

You shouldn’t need a thread to make an asynchronous GUI. You should be able
to use a function such as select() to avoid stalling your main loop by
inspecting the pipe for activity. Using a background thread could be
sub-optimal because your “main” thread might soak up lots of processing time
by not blocking (even for short periods of time) which might cause the
background process to take a long time to deliver its input (depending on
the nature).

I would confidently say that threads are the wrong solution for what you are
trying to do. After all, once you’ve read the data from the pipe you still
need to safely give it to the GUI to use, and this involves lots of the same
problems that you are using the thread to avoid! Well, the SDL event system
might make it not too difficult to do it that way, as you have the classic
producer/consumer model to base your program off. But select() in a single
thread is better again, I think.

– BrianOn 31 August 2010 18:28, dekyco wrote:

This is working, at least the program is not segfaulting.It is starting
and immediatly exits when called
by Init():

Code:

[New Thread 0xb6c42b90 (LWP 27268)]
I am in the thread.
[Thread 0xb6c42b90 (LWP 27268) exited]

When started with a click on some gui element it runs independently from
the rest of the program,
so I can move window,change gui ‘levels’,click other buttons etc without
blocking (for now).

Thread is opening a pipe (popen) for another program and the output of this
is displayed with SDL - so I am using SDL
as a gui frontend for command line.The goal is to have a non-blocking gui
frontend for command line program.
So far command line is displaying its output and SDL is not blocking during
this time but who knows…maybe
I am at least on the right track with this.

You are wright I do not have expirience with this at all…

Is SDL_WaitThread(thread, NULL) some sort of ‘pause’ for thread?

dekyco


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Ok I will look into that,thank you for the tip. Have another question about threads in the meanwhile…

When I kill the thread, the program which was spawned with popen() remains active.I am using pclose in the
thread destructor to close pipe handler.So how can I kill thisprogram?

In this case I am using ‘tree /’ command which gives me enough time to test the thread behaviour
in debugger.When I kill the thread the ‘tree’ stays active in process list.How can I avoid this?

dekyco

Killing threads is usually a very bad idea. It should be reserved for
emergency shutdown code, first you ask the thread to quit nicely, if
it refuses to respond after 10-30 seconds then just force kill it.
Such hung threads indicate programming bugs most of the time, in
particular liveness bugs. Your threads should periodically wake to
check if a request to shutdown has been received (maybe every 500
milliseconds or something like that). SDL_KillThread() is deprecated
anyway I believe, if not removed entirely from SDL 1.3.

Force-killing a thread can cause critical deadlocks in other threads,
leading to a cascade where you end up killing all your threads. It is
arguably better to just let the user terminate the process externally
than to try and fix this yourself.

In any case, you have to be careful with destructors and threads. You
are passing a pointer to a thread, you must ensure that this pointer
remains valid - along with all data members. It sounds like pclose()
is reasonably safe to call, but certainly having another thread
running while the destructor for its data is running would be a bad
idea.

The documentation for pclose() says that it waits for the process to
finish. I would expect most console programs to halt abruptly if their
stdout was closed, but maybe tree doesn’t detect (or handle) errors
with output. In any case, this is getting a little off-topic for the
SDL list, there are *nix lists which would be better suited to talking
about the details of inter-process communication and the functions you
are using, which are beyond SDL’s scope.

– BrianOn 31 August 2010 23:33, dekyco wrote:

Ok I will look into that,thank you for the tip. Have another question about
threads in the meanwhile…

When I kill the thread, the program which was spawned with popen() remains
active.I am using pclose in the
thread destructor to close pipe handler.So how can I kill thisprogram?

In this case I am using ‘tree /’ command which gives me enough time to test
the thread behaviour
in debugger.When I kill the thread the ‘tree’ stays active in process
list.How can I avoid this?

dekyco

Ok Brian, thank you very much for now.

dekyco