[gnome-sudoku] SudokuGenerator: Use multiple threads for puzzle generation
- From: Parin Porecha <parinporecha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-sudoku] SudokuGenerator: Use multiple threads for puzzle generation
- Date: Mon, 18 Aug 2014 18:00:04 +0000 (UTC)
commit 1e7d1ec53162b23a5bb809756e66103c7271d3e1
Author: Parin Porecha <parinporecha gmail com>
Date: Mon Aug 18 19:34:22 2014 +0200
SudokuGenerator: Use multiple threads for puzzle generation
https://bugzilla.gnome.org/show_bug.cgi?id=580056
configure.ac | 2 +
data/print-games.ui | 9 +++++
lib/Makefile.am | 1 +
lib/sudoku-generator.vala | 75 +++++++++++++++++++++++++++++++++++++++++++++
src/gnome-sudoku.vala | 10 +++++-
src/sudoku-printer.vala | 39 +++++++++++++++++------
6 files changed, 124 insertions(+), 12 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 96073d2..3394e8d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,6 +42,8 @@ PKG_CHECK_MODULES(LIBSUDOKU, [
json-glib-1.0
])
+AC_SUBST([GLIB_REQUIRED])
+
AC_PATH_PROG([APPDATA_VALIDATE], [appdata-validate], [/bin/true])
AC_PATH_PROG([DESKTOP_FILE_VALIDATE], [desktop-file-validate], [/bin/true])
diff --git a/data/print-games.ui b/data/print-games.ui
index 62a5ef1..d204313 100644
--- a/data/print-games.ui
+++ b/data/print-games.ui
@@ -54,6 +54,15 @@
<property name="pack_type">start</property>
</packing>
</child>
+ <child>
+ <object class="GtkSpinner" id="spinner">
+ <property name="valign">center</property>
+ <property name="visible">False</property>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
</object>
</child>
<child internal-child="vbox">
diff --git a/lib/Makefile.am b/lib/Makefile.am
index e0af6eb..b994bb4 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -26,6 +26,7 @@ libsudoku_la_VALAFLAGS = \
--pkg gio-2.0 \
--pkg json-glib-1.0 \
--pkg posix \
+ --target-glib=$(GLIB_REQUIRED) \
--header=libsudoku.h \
--vapi=libsudoku.vapi
diff --git a/lib/sudoku-generator.vala b/lib/sudoku-generator.vala
index c53a406..100f6f6 100644
--- a/lib/sudoku-generator.vala
+++ b/lib/sudoku-generator.vala
@@ -1,5 +1,7 @@
/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+using Gee;
+
public class SudokuGenerator : Object
{
private SudokuGenerator () {
@@ -22,6 +24,38 @@ public class SudokuGenerator : Object
return board;
}
+ public async static SudokuBoard[] generate_boards_async (int nboards, DifficultyCategory category)
throws ThreadError
+ {
+ var boards_list = new ArrayList<SudokuBoard> ();
+ var boards = new SudokuBoard[nboards];
+ Thread<void*> threads[16];
+
+ var ncpu_usable = int.max (1, get_number_of_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, ref boards_list,
generate_boards_async.callback);
+ threads[i] = new Thread<void*> ("Generator thread", gen_thread.run);
+ }
+
+ // Relinquish the CPU, so that the generated threads can run
+ for (var i = 0; i < nthreads; i++)
+ {
+ yield;
+ threads[i].join ();
+ }
+
+ for (var i = 0; i < boards_list.size; i++)
+ boards[i] = boards_list[i];
+ return boards;
+ }
+
public static void print_stats (SudokuBoard board)
{
var cells = board.get_cells ();
@@ -38,4 +72,45 @@ public class SudokuGenerator : Object
{
return QQwing.get_version ();
}
+
+ private static int get_number_of_processors ()
+ {
+ int ncpu;
+ string nproc_stdout;
+
+ try {
+ Process.spawn_command_line_sync ("nproc", out nproc_stdout);
+ ncpu = int.parse (nproc_stdout);
+ } catch (SpawnError e) {
+ warning ("Call to nproc failed. Puzzles will be generated in a single thread");
+ ncpu = 1;
+ }
+
+ return ncpu;
+ }
+}
+
+public class GeneratorThread : Object
+{
+ private int nsudokus;
+ private DifficultyCategory level;
+ private ArrayList<SudokuBoard> boards_list;
+ private SourceFunc callback;
+
+ public GeneratorThread (int nsudokus, DifficultyCategory level, ref ArrayList<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((owned) callback);
+ return null;
+ }
}
diff --git a/src/gnome-sudoku.vala b/src/gnome-sudoku.vala
index 2b7e860..c27542c 100644
--- a/src/gnome-sudoku.vala
+++ b/src/gnome-sudoku.vala
@@ -296,7 +296,15 @@ public class Sudoku : Gtk.Application
// has been set to integers corresponding to the enums.
// Following line converts those ints to their DifficultyCategory
var selected_difficulty = (DifficultyCategory) difficulty.get_int32 ();
- start_game (SudokuGenerator.generate_board (selected_difficulty));
+
+ SudokuGenerator.generate_boards_async.begin (1, selected_difficulty, (obj, res) => {
+ try {
+ var gen_boards = SudokuGenerator.generate_boards_async.end (res);
+ start_game (gen_boards[0]);
+ } catch (ThreadError e) {
+ error ("Thread error: %s", e.message);
+ }
+ });
}
private void reset_cb ()
diff --git a/src/sudoku-printer.vala b/src/sudoku-printer.vala
index 5ccd2f3..1abbe98 100644
--- a/src/sudoku-printer.vala
+++ b/src/sudoku-printer.vala
@@ -229,6 +229,8 @@ public class GamePrinter: GLib.Object
private RadioButton intermediate_button;
private RadioButton expert_button;
+ private Spinner spinner;
+
private const string DIFFICULTY_KEY_NAME = "print-multiple-sudoku-difficulty";
public GamePrinter (SudokuSaver saver, ref ApplicationWindow window)
@@ -279,6 +281,8 @@ public class GamePrinter: GLib.Object
nsudokus_button = builder.get_object ("sudokusToPrintSpinButton") as SpinButton;
wrap_adjustment ("print-multiple-sudokus-to-print", nsudokus_button.get_adjustment ());
+
+ spinner = builder.get_object ("spinner") as Spinner;
}
private void wrap_adjustment (string key_name, Adjustment action)
@@ -297,7 +301,6 @@ public class GamePrinter: GLib.Object
var nsudokus = (int) nsudokus_button.get_adjustment ().get_value ();
DifficultyCategory level;
- var boards = new SudokuBoard[nsudokus];
if (simple_button.get_active ())
level = DifficultyCategory.SIMPLE;
@@ -312,18 +315,32 @@ public class GamePrinter: GLib.Object
settings.set_enum (DIFFICULTY_KEY_NAME, level);
- for (var i = 0; i < nsudokus; i++)
- boards[i] = SudokuGenerator.generate_board (level);
+ spinner.visible = true;
+ spinner.active = true;
+ spinner.show ();
+ spinner.start ();
+ dialog.sensitive = false;
- SudokuPrinter printer = new SudokuPrinter (boards, ref window);
+ SudokuGenerator.generate_boards_async.begin(nsudokus, level, (obj, res) => {
+ try {
+ var boards = SudokuGenerator.generate_boards_async.end(res);
- PrintOperationResult result = printer.print_sudoku ();
- if (result == PrintOperationResult.APPLY)
- {
- dialog.hide ();
- foreach (SudokuBoard board in boards)
- saver.add_game_to_finished (new SudokuGame (board));
- }
+ spinner.stop ();
+ spinner.hide ();
+ dialog.sensitive = true;
+
+ SudokuPrinter printer = new SudokuPrinter (boards, ref window);
+ PrintOperationResult result = printer.print_sudoku ();
+ if (result == PrintOperationResult.APPLY)
+ {
+ dialog.hide ();
+ foreach (SudokuBoard board in boards)
+ saver.add_game_to_finished (new SudokuGame (board));
+ }
+ } catch (ThreadError e) {
+ error ("Thread error: %s\n", e.message);
+ }
+ });
}
public void run_dialog ()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]