[gnome-sudoku] generator: use a thread pool



commit a12ca3b0b23d23c1a77053b4ab086ca49830c9b4
Author: Michael Catanzaro <mcatanzaro gnome org>
Date:   Sun Oct 5 13:01:17 2014 -0500

    generator: use a thread pool
    
    The current code blocks the UI thread briefly if the generator threads
    do not finish in order.

 lib/sudoku-generator.vala |   64 +++++++++++++++++++--------------------------
 src/print-dialog.vala     |    2 +-
 2 files changed, 28 insertions(+), 38 deletions(-)
---
diff --git a/lib/sudoku-generator.vala b/lib/sudoku-generator.vala
index e7ac71a..1acdaba 100644
--- a/lib/sudoku-generator.vala
+++ b/lib/sudoku-generator.vala
@@ -23,14 +23,16 @@ using Gee;
 
 public class SudokuGenerator : Object
 {
-    public class GeneratorThread : Object
+    private class Worker : Object
     {
         private int nsudokus;
         private DifficultyCategory level;
+        // FIXME Require Gee.ConcurrentList and remove the mutex
         private Gee.List<SudokuBoard> boards_list;
+        private static Mutex mutex;
         private unowned SourceFunc callback;
 
-        public GeneratorThread (int nsudokus, DifficultyCategory level, Gee.List<SudokuBoard> boards_list, 
SourceFunc callback)
+        public Worker (int nsudokus, DifficultyCategory level, Gee.List<SudokuBoard> boards_list, SourceFunc 
callback)
         {
             this.nsudokus = nsudokus;
             this.level = level;
@@ -38,17 +40,22 @@ public class SudokuGenerator : Object
             this.callback = callback;
         }
 
-        public void* run ()
+        public void run ()
         {
-            for (var i = 0; i < nsudokus; i++)
-                boards_list.add (SudokuGenerator.generate_board (level));
-
-            Idle.add(() => {
-                callback ();
-                return Source.REMOVE;
-            });
-
-            return null;
+            // Generating a board takes a relatively long time.
+            var board = SudokuGenerator.generate_board (level);
+            mutex.lock ();
+            boards_list.add (board);
+            if (boards_list.size == nsudokus)
+            {
+                // We've added the final board to the list.
+                // Finish the call to generate_boards_async.
+                Idle.add (() => {
+                    callback ();
+                    return Source.REMOVE;
+                });
+            }
+            mutex.unlock ();
         }
     }
 
@@ -72,36 +79,19 @@ public class SudokuGenerator : Object
         return board;
     }
 
-    public async static SudokuBoard[] generate_boards_async (int nboards, DifficultyCategory category) 
throws ThreadError
+    public async static Gee.List<SudokuBoard> generate_boards_async (int nboards, DifficultyCategory 
category) throws ThreadError
     {
-// FIXME broken: not threadsafe!
-        var boards_list = new ArrayList<SudokuBoard> ();
-        var boards = new SudokuBoard[nboards];
-        var threads = new ArrayList<Thread<void*>> ();
-
-        var ncpu_usable = int.max (1, (int) get_num_processors () - 1);
-        var nthreads = int.min (ncpu_usable, nboards);
-        var base_nsudokus_each = nboards / nthreads;
-        var remainder = nboards % nthreads;
-        var nsudokus_per_thread = base_nsudokus_each;
-
-        for (var i = 0; i < nthreads; i++)
-        {
-            if (i > (nthreads - remainder - 1))
-                nsudokus_per_thread = base_nsudokus_each + 1;
-            var gen_thread = new GeneratorThread (nsudokus_per_thread, category, boards_list, 
generate_boards_async.callback);
-            threads.add (new Thread<void*> ("Generator thread", gen_thread.run));
-        }
+        var boards = new ArrayList<SudokuBoard> ();
+        var pool = new ThreadPool<Worker>.with_owned_data ((worker) => {
+            worker.run ();
+        }, (int) get_num_processors (), false);
 
-        // Relinquish the CPU, so that the generated threads can run
-        for (var i = 0; i < nthreads; i++)
+        for (var i = 0; i < nboards; i++)
         {
-            yield;
-            threads.get(i).join ();
+            pool.add (new Worker (nboards, category, boards, generate_boards_async.callback));
         }
 
-        for (var i = 0; i < boards_list.size; i++)
-            boards[i] = boards_list[i];
+        yield;
         return boards;
     }
 
diff --git a/src/print-dialog.vala b/src/print-dialog.vala
index aa588ba..cb0e58e 100644
--- a/src/print-dialog.vala
+++ b/src/print-dialog.vala
@@ -129,7 +129,7 @@ once = true;
                 spinner.hide ();
                 sensitive = true;
 
-                var printer = new SudokuPrinter (new Gee.ArrayList<SudokuBoard>.wrap (boards), this);
+                var printer = new SudokuPrinter (boards, this);
                 if (printer.print_sudoku () == Gtk.PrintOperationResult.APPLY)
                 {
                     foreach (SudokuBoard board in boards)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]