www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - resume a calling thread

reply Daniel919 web.de writes:
Hi, I found a piece of code in the digitalmars.D.learn group about threads.

I didn't like the way it was checking whether one of the threads was stilling
running. It was something like: while (!allDone) { another check ... and
immediately repeat this loop } So it wasted 100% CPU.
Sure, I could have put a msleep(100) into it, but I thought about something
else: a way to make it respond without any delay.
This is the code up to now:
-----------------------------------------------------------------
import std.thread, std.stdio, std.c.time;

class Mainthread : Thread
{
this ()
{
super(&thread_main);
}

int thread_main ()
{
writefln("main thread started");

Subthread sub[];
uint allDone = 0;

// Create some threads of different durations.
sub ~= new Subthread(5);
sub ~= new Subthread(1);
sub ~= new Subthread(2);
sub ~= new Subthread(4);

// Start all the threads running.
foreach(Subthread t; sub)
{
writefln("Starting #%d for %d seconds", t.id, t.init_value);
t.start();
}

while (!allDone) {
writefln("loop");
allDone = 1;
foreach(int i, Subthread t; sub)
{
if (t.getState != Thread.TS.TERMINATED) allDone = 0;
};
pause();
writefln("pause done");
};

writefln("allDone");

// Ensure that they clean up.
foreach(int i, Subthread t; sub)
{
writefln("final wait #%d", t.id);
t.wait();
delete t;
};

writefln("cleanup done");
}
} 



class Subthread : Thread
{
private{
static int g_id;
static const uint OneSecond = 1000;
int m_id;
int m_V;
}

this (int V)
{
m_id = ++g_id;
m_V = V;

// Register callback function with Thread Central.
super(&thread_main);

writefln("create thread #%d", m_id);
}

~this()
{
writefln("destroy thread #%d", m_id);
}

int id()
{
return m_id;
}

int init_value()
{
return m_V;
}

int thread_main ()
{
writefln("in thread_main #%d", m_id);
for(int i = 0; i < m_V; i++)
{
msleep(OneSecond); // Do something very important
yield(); // Let someone else have some play time.
}
writefln("out thread_main #%d", m_id);
mainthread.resume();
return 0;
}
}



Mainthread mainthread;

int main ()
{
Mainthread mainthread = new Mainthread();
mainthread.start();
msleep(1000000);
return 0;
}
-----------------------------------------------------------------

So you see, instead of doing msleep() in main, I create a mainthread which then
spawns the other threads (Subthread).
In the "while (!allDone) ..." loop I pause() the mainthread, and wait for each
subthread to finish and then call resume() for the mainthread to let this loop
run again.
But unfortunately it's not working, I get this:
Error: Access Violation
when the subthread calls: mainthread.resume();

Any ideas how I can get this working ?

I would really appreciate your help, thanks !
/Daniel
Jun 06 2006
parent Sean Kelly <sean f4.ca> writes:
pause and resume are really intended for use by the garbage collector 
and shouldn't really be called in user code, as pausing a thread that's 
executing a system call or holding a lock can cause other threads to 
hang waiting for that resource.  I'm not sure how well it applies to 
Phobos, but Ares has a ThreadGroup class specifically for what you're 
trying to do.  Use is simple:

     void main() {
         void run() {
             printf( "running\n" );
             Thread.sleep( 10000 );
             printf( "done\n" );
         }

         ThreadGroup g = new ThreadGroup;
         g.create( &run );
         g.create( &run );
         g.joinAll( false );
     }

The 'false' paramater to joinAll removes thread references when they 
have completed, allowing the objects to be collected by the GC. 
Currently, this works via foreach and Walter has said that altering a 
data structure during foreach is technically illegal, but I haven't 
found the time to develop a workaround.  In any case, it works just fine 
at the moment.


Sean
Jun 06 2006