[gnome-sudoku/gnome-3-14] generator: use a thread pool



commit 238fa01bb246d4f64390bf9233c892cb2c302c66
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. Oh and it's also not safe.

 lib/sudoku-generator.vala |   98 ++++++++++++++++++++-------------------------
 src/print-dialog.vala     |    2 +-
 2 files changed, 45 insertions(+), 55 deletions(-)
---
diff --git a/lib/sudoku-generator.vala b/lib/sudoku-generator.vala
index 7dcb036..7bd8e18 100644
--- a/lib/sudoku-generator.vala
+++ b/lib/sudoku-generator.vala
@@ -23,6 +23,42 @@ using Gee;
 
 public class SudokuGenerator : 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 Worker (int nsudokus, DifficultyCategory level, Gee.List<SudokuBoard> boards_list, SourceFunc 
callback)
+        {
+            this.nsudokus = nsudokus;
+            this.level = level;
+            this.boards_list = boards_list;
+            this.callback = callback;
+        }
+
+        public void run ()
+        {
+            // 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 ();
+        }
+    }
+
     private SudokuGenerator () {
     }
 
@@ -43,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 boards = new ArrayList<SudokuBoard> ();
+        var pool = new ThreadPool<Worker>.with_owned_data ((worker) => {
+            worker.run ();
+        }, (int) get_num_processors (), false);
 
-        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++)
+        for (var i = 0; i < nboards; 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));
+            pool.add (new Worker (nboards, category, boards, generate_boards_async.callback));
         }
 
-        // Relinquish the CPU, so that the generated threads can run
-        for (var i = 0; i < nthreads; i++)
-        {
-            yield;
-            threads.get(i).join ();
-        }
-
-        for (var i = 0; i < boards_list.size; i++)
-            boards[i] = boards_list[i];
+        yield;
         return boards;
     }
 
@@ -93,32 +112,3 @@ public class SudokuGenerator : Object
         return QQwing.get_version ();
     }
 }
-
-public class GeneratorThread : Object
-{
-    private int nsudokus;
-    private DifficultyCategory level;
-    private Gee.List<SudokuBoard> boards_list;
-    private unowned SourceFunc callback;
-
-    public GeneratorThread (int nsudokus, DifficultyCategory level, Gee.List<SudokuBoard> boards_list, 
SourceFunc callback)
-    {
-        this.nsudokus = nsudokus;
-        this.level = level;
-        this.boards_list = boards_list;
-        this.callback = callback;
-    }
-
-    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;
-    }
-}
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]