Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>If you have access to a <a href="http://en.wikipedia.org/wiki/Cilk" rel="nofollow noreferrer">work stealing framework</a> in your environment (for example, <code>Cilk</code> if you are in C, or the <a href="http://gee.cs.oswego.edu/dl/concurrency-interest/" rel="nofollow noreferrer">fork/join framework</a> of Doug Lea in Java), you can easily get a simple and clean solution (compared to low-level ad-hoc attempts, which you will probably will have to do if you can't use something like that), which give you automatic load balancing and good data locality.</p> <p>Here is a high level description of a solution: you start one thread per core. Each one gets assigned a list till they are exhausted (many ways to do this - that's the task of very good concurrent queuing mechanisms, and that's a reason you would like to avoid do-it-yourself solutions if possible). Each worker goes through the rows of the lists one by one: - Two queues are maintained, one for those jobs before a <code>signal</code> token, and one or those after it. - When a job is encountered, it is <em>forked</em>, and added to the respective queue (depending on whether we saw a <code>signal</code> token or not) - When a <code>wait</code> token is encountered, we join all jobs before the signal (that's the semantics you describe if I understood correctly). Note that in the code I use <code>helpJoin()</code>, it means that the thread will actually help (by popping forked tasks and executing them till the join can proceed)</p> <p>"Fork" means putting the task in a thread-local queue, which will either be executed by the thread itself later, or it can be stolen by another thread that looks for some work to do.</p> <p>For illustration purposes, here is a working ~80 lines simulation of this scenario, using the aforementioned java framework. It creates as many threads as available cores, and some lists, and starts executing them. Note how simple the run() method is - while it still has the benefits of load balancing and that threads mostly execute tasks from their own list, unless they run out of work and start stealing to get some. Of course, if you are not in Java or C, you would have to find a similar framework, but the same set of core ideas would similarly simplify your code regardless of the language.</p> <pre><code>import java.util.*; import java.util.concurrent.*; import jsr166y.ForkJoinPool; import jsr166y.ForkJoinTask; import jsr166y.RecursiveTask; public class FJTest { public static void main(String[] args) throws Exception { Iterable&lt;List&lt;TaskType&gt;&gt; lists = createLists(10); ForkJoinPool pool = new ForkJoinPool(); for (final List&lt;TaskType&gt; list : lists) { pool.submit(new Runnable() { public void run() { List&lt;ForkJoinTask&gt; beforeSignal = new ArrayList&lt;ForkJoinTask&gt;(); List&lt;ForkJoinTask&gt; afterSignal = new ArrayList&lt;ForkJoinTask&gt;(); boolean signaled = false; for (TaskType task : list) { switch (task) { case JOB: ForkJoinTask job = new Job(); if (signaled == false) beforeSignal.add(job); else afterSignal.add(job); job.fork(); break; case SIGNAL: signaled = true; break; case WAIT: signaled = false; for (ForkJoinTask t : beforeSignal) { t.helpJoin(); } beforeSignal = afterSignal; afterSignal = new ArrayList&lt;ForkJoinTask&gt;(); } } } }); } pool.shutdown(); pool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } private static Iterable&lt;List&lt;TaskType&gt;&gt; createLists(int size) { List&lt;List&lt;TaskType&gt;&gt; tasks = new ArrayList&lt;List&lt;TaskType&gt;&gt;(); for (int i = 0; i &lt; size; i++) { tasks.add(createSomeList()); } return tasks; } private static List&lt;TaskType&gt; createSomeList() { return Arrays.asList( TaskType.JOB, TaskType.JOB, TaskType.SIGNAL, TaskType.JOB, TaskType.WAIT, TaskType.JOB); } } enum TaskType { JOB, SIGNAL, WAIT; } class Job extends RecursiveTask&lt;Void&gt; { @Override protected Void compute() { long x = 1; for (long i = 1; i &lt; 200000001; i++) { x = i * x; } System.out.println(x); //just to use x return null; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload