digitalmars.D - resume a calling thread
- Daniel919 web.de (113/113) Jun 06 2006 Hi, I found a piece of code in the digitalmars.D.learn group about threa...
- Sean Kelly (24/24) Jun 06 2006 pause and resume are really intended for use by the garbage collector
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) { 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) { 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); } ~this() { } int id() { return m_id; } int init_value() { return m_V; } int thread_main () { for(int i = 0; i < m_V; i++) { msleep(OneSecond); // Do something very important yield(); // Let someone else have some play time. } 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
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