First experience with Threads

Era Scarecrow rtcvb32 at yahoo.com
Sat Oct 6 06:17:04 PDT 2012


  Just a little experience and perhaps some help on the subject. 
This is a partial repost from another forum too so. I've always 
saw how much threading was an annoyance trying to follow along 
(the API alone) but programming it is more annoying. I've never 
actually done multi-thread programming so this is a first for me.


  First the problem. Trying to load up a data structure (that's 
fairly big) can take a fair amount of time, but if the records 
and structures never need to touch eachother, there's no reason 
they cannot be handled on separate cores/threads (or that's my 
logic on it anyways).


  In order to try and use more cores, I've split off the loading 
and unpacking stages as separate. So first off within half a 
second the whole memory is filled with 80Mb of data and all the 
records are separated. Now that they are separated, they can all 
be unpacked by the different cores.

  Part of a problem is when the thread activates, just because you 
start a thread doesn't mean it runs right away (it will run when 
it's ready), an any data that still relies on it via a delegate 
becomes a violate pointer data (At least in VisualD) and that 
data may change. So...

[code]
   class Record {
     //and stuff
     void loadSubRecords();
   }
   Record[] recordList; //and stuff

   foreach(rec; recordList) {
     Thread th = new Thread( () {rec.loadSubRecords()} );
     th.start();
   }
[/code]

  Rec (and even ref rec) may change at any time (Worse is during 
it's update or before the thread starts). So if we go with to 
copying an index instead it does improve a bit. So long as the 
data is copied before the next foreach loop it's fine, otherwise 
I may still change and it may do something unwanted.

[code]
   foreach(i, rec; recordList) {
     Thread th = new Thread( ()
        {
          int index = i;
          recordList[index].loadSubRecords();
        });
     th.start();
   }
[/code]

Several other combinations came up. I think I found an easy way 
to handle it without adding in unneeded mutexes and whatnot. What 
seems to work is if I pack all the data for the job I need in a 
structure, and have that structure start the thread (inside), 
then the chances of the problem happening go away (hopefully 
completely).

[code]
   //or something similar
   struct Packed {
     Thread thread;
     Record record;
     void run() {
       assert(record);
       thread = new Thread( (){record.loadSubRecords();} );
       thread.start();
     }
   }

   //bad way of thread handling, but makes sense.
   Packed[] obj;
   obj.length = recordList.length;

   foreach(i, rec; recordList) {
     obj[i].record = rec; //class is reference type remember
     obj[i].run(); //returns right away, but thread is running too
   }
   threads_joinAll();
[/code]

  So long as the records (and subrecords) never touch eachother 
then mutexes and semephores aren't needed 90% of the time.

  Now since the record count in the original file is 40k, having 
40k of threads not only is dumb, but also expensive to set up. So 
instead I set up job groups.

[code]
   struct PackedList {
     Thread thread;
     Record[] recordList;

     void runWork() {
       foreach(rec; recordList)
         rec.loadSubRecords();
     }

     void run() {
       assert(recordList);
       thread = new Thread( (){this.runWork();} );
       thread.start();
     }
   }
[/code]

  With this basic idea, drop a thousand in one PackedList and 
start it, then grab another thousand and drop them into another 
PackedList. They'll run until their workload is done.

  Is there a suggested magic number of how many threads per core 
you should use? If you have say a quad core, you can have 4 
threads going (obviously) but if they go to sleep waiting on 
system resources or something (loading a file, saving, something 
other), then the core may be unused. It makes sense to have 2 per 
core since then if it gets silent it has another it can pick up 
on. I'm guessing 2-4 would be the number of threads to do this 
type of work.


More information about the Digitalmars-d-learn mailing list