[f-spot/mipmapped-loading: 12/12] Simplify Task, add Threadpool support.
- From: Ruben Vermeersch <rubenv src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [f-spot/mipmapped-loading: 12/12] Simplify Task, add Threadpool support.
- Date: Fri, 2 Jul 2010 13:56:20 +0000 (UTC)
commit 12080702912bb387d7eaee825a82faeabbe3dab0
Author: Ruben Vermeersch <ruben savanne be>
Date: Fri Jul 2 15:53:30 2010 +0200
Simplify Task, add Threadpool support.
src/Import/ImportController.cs | 4 +--
src/Jobs/SyncMetadataJob.cs | 2 -
src/Loaders/XdgThumbnailLoader.cs | 2 +-
src/Tasks/Task.cs | 40 ++++++++++++++-------
src/Tasks/Tests/TaskPriorityTests.cs | 2 +-
src/Tasks/Tests/TaskTests.cs | 2 +-
src/Tasks/WorkerThreadTask.cs | 64 +++++++++++-----------------------
src/ThumbnailCommand.cs | 4 +--
src/Widgets/Filmstrip.cs | 6 +--
src/Widgets/IconView.cs | 6 +--
10 files changed, 57 insertions(+), 75 deletions(-)
---
diff --git a/src/Import/ImportController.cs b/src/Import/ImportController.cs
index 471a6fb..b05ea3c 100644
--- a/src/Import/ImportController.cs
+++ b/src/Import/ImportController.cs
@@ -340,9 +340,7 @@ namespace FSpot.Import
{
var loader = App.Instance.Loaders.RequestLoader (photo.DefaultVersion);
var preview_task = loader.FindBestPreview (256, 256);
- var task = new WorkerThreadTask<bool> (() => { preview_task.Result.Dispose (); return false; }) {
- Priority = TaskPriority.Background
- };
+ var task = new Task<bool> (() => { preview_task.Result.Dispose (); return false; }, TaskPriority.Background);
preview_task.ContinueWith (task);
}
diff --git a/src/Jobs/SyncMetadataJob.cs b/src/Jobs/SyncMetadataJob.cs
index 2180160..79882ef 100644
--- a/src/Jobs/SyncMetadataJob.cs
+++ b/src/Jobs/SyncMetadataJob.cs
@@ -46,8 +46,6 @@ namespace FSpot.Jobs {
void WriteMetadataToImage (Photo photo)
{
- string path = photo.DefaultVersion.Uri.LocalPath;
-
Tag [] tags = photo.Tags;
string [] names = new string [tags.Length];
diff --git a/src/Loaders/XdgThumbnailLoader.cs b/src/Loaders/XdgThumbnailLoader.cs
index eceb75c..9f92e15 100644
--- a/src/Loaders/XdgThumbnailLoader.cs
+++ b/src/Loaders/XdgThumbnailLoader.cs
@@ -20,7 +20,7 @@ namespace FSpot.Loaders
public Task<Pixbuf> FindBestPreview (int width, int height)
{
- return new WorkerThreadTask<Pixbuf> (() => {
+ return new Task<Pixbuf> (() => {
var size = (width > 128 || height > 128) ? ThumbnailSize.Large : ThumbnailSize.Normal;
var pixbuf = XdgThumbnailSpec.LoadThumbnail (Loadable.Uri, size);
return pixbuf;
diff --git a/src/Tasks/Task.cs b/src/Tasks/Task.cs
index d5cce2f..6c390e9 100644
--- a/src/Tasks/Task.cs
+++ b/src/Tasks/Task.cs
@@ -26,6 +26,13 @@ namespace FSpot.Tasks
void Reschedule ();
}
+ public interface IScheduler
+ {
+ void Schedule (Task task);
+ void Unschedule (Task task);
+ void Reschedule (Task task);
+ }
+
public enum TaskState
{
Pending,
@@ -42,10 +49,18 @@ namespace FSpot.Tasks
Interactive
}
- public abstract class Task<T> : Task, ISchedulable, IChildrenHandling
+ public class Task<T> : Task, ISchedulable, IChildrenHandling
{
+ static IScheduler DefaultScheduler {
+ get { return WorkerThreadTaskScheduler.Instance; }
+ }
+
+ public delegate T TaskHandler ();
+
public bool CancelWithChildren { get; set; }
public Task Parent { get; set; }
+ public IScheduler Scheduler { get; set; }
+ public TaskHandler Handler { get; set; }
private List<Task> Children { get; set; }
@@ -80,13 +95,18 @@ namespace FSpot.Tasks
private EventWaitHandle WaitEvent { get; set; }
- public Task ()
+ public Task (TaskHandler handler) : this (handler, TaskPriority.Normal) {
+ }
+
+ public Task (TaskHandler handler, TaskPriority priority)
{
CancelWithChildren = false;
Children = new List<Task> ();
WaitEvent = new ManualResetEvent (false);
State = TaskState.Pending;
- Priority = TaskPriority.Normal;
+ Priority = priority;
+ Scheduler = DefaultScheduler;
+ Handler = handler;
}
public void Start ()
@@ -175,7 +195,7 @@ namespace FSpot.Tasks
return;
try {
- result = InnerExecute ();
+ result = Handler ();
State = TaskState.Completed;
foreach (var child in Children) {
@@ -189,8 +209,6 @@ namespace FSpot.Tasks
}
}
- protected abstract T InnerExecute ();
-
#region Scheduling
void ISchedulable.Schedule ()
@@ -200,25 +218,21 @@ namespace FSpot.Tasks
if (State != TaskState.Pending)
throw new Exception ("Can only schedule pending tasks!");
State = TaskState.Scheduled;
- InnerSchedule ();
+ Scheduler.Schedule (this);
}
void ISchedulable.Unschedule ()
{
if (State == TaskState.Scheduled)
State = TaskState.Pending;
- InnerUnschedule ();
+ Scheduler.Unschedule (this);
}
void ISchedulable.Reschedule ()
{
- InnerReschedule ();
+ Scheduler.Reschedule (this);
}
- protected abstract void InnerSchedule ();
- protected abstract void InnerUnschedule ();
- protected abstract void InnerReschedule ();
-
#endregion
}
diff --git a/src/Tasks/Tests/TaskPriorityTests.cs b/src/Tasks/Tests/TaskPriorityTests.cs
index 16e4415..38acbd0 100644
--- a/src/Tasks/Tests/TaskPriorityTests.cs
+++ b/src/Tasks/Tests/TaskPriorityTests.cs
@@ -179,7 +179,7 @@ namespace FSpot.Tasks.Tests
Assert.AreEqual (new Task [] { task1, task2 }, WorkerThreadTaskScheduler.Instance.Tasks);
}
- private class TestTask : WorkerThreadTask<bool> {
+ private class TestTask : Task<bool> {
public TestTask () : base (() => true) {
}
diff --git a/src/Tasks/Tests/TaskTests.cs b/src/Tasks/Tests/TaskTests.cs
index f70947d..6b74fcd 100644
--- a/src/Tasks/Tests/TaskTests.cs
+++ b/src/Tasks/Tests/TaskTests.cs
@@ -96,7 +96,7 @@ namespace FSpot.Tasks.Tests
Assert.AreEqual (TaskState.Cancelled, t2.State);
}
- class SimpleTask<T> : WorkerThreadTask<T> {
+ class SimpleTask<T> : Task<T> {
string label = null;
public SimpleTask (TaskHandler h) : base (h) {
diff --git a/src/Tasks/WorkerThreadTask.cs b/src/Tasks/WorkerThreadTask.cs
index 7829b16..bb22922 100644
--- a/src/Tasks/WorkerThreadTask.cs
+++ b/src/Tasks/WorkerThreadTask.cs
@@ -7,9 +7,9 @@ using System.Collections.Generic;
namespace FSpot.Tasks
{
/// <summary>
- /// Simple task scheduler that executes all tasks on one worker thread.
+ /// Simple task scheduler that pumps the threadpool.
/// </summary>
- internal class WorkerThreadTaskScheduler {
+ internal class WorkerThreadTaskScheduler : IScheduler {
static object sync_root = new object ();
#region Singleton Pattern
@@ -42,7 +42,7 @@ namespace FSpot.Tasks
internal IntervalHeap<Task> heap = new IntervalHeap<Task> ();
- internal void Schedule (Task task)
+ public void Schedule (Task task)
{
lock (heap) {
heap.Push (task, (int) task.Priority);
@@ -50,14 +50,14 @@ namespace FSpot.Tasks
}
}
- internal void Unschedule (Task task)
+ public void Unschedule (Task task)
{
lock (heap) {
heap.Remove (task);
}
}
- internal void Reschedule (Task task)
+ public void Reschedule (Task task)
{
lock (heap) {
heap.Remove (task);
@@ -85,6 +85,9 @@ namespace FSpot.Tasks
internal WorkerThreadTaskScheduler (bool start_worker)
{
+ max_tasks = Environment.ProcessorCount * 2;
+ Log.DebugFormat ("Doing at most {0} tasks", max_tasks);
+
// Not starting the worker means that the scheduler won't work,
// but this can be useful for unit tests.
if (start_worker) {
@@ -94,7 +97,10 @@ namespace FSpot.Tasks
EventWaitHandle wait = new AutoResetEvent (false);
Thread worker;
+
volatile bool should_halt = false;
+ int max_tasks = 0;
+ volatile int tasks_queued = 0;
void SchedulerWorker ()
{
@@ -105,12 +111,19 @@ namespace FSpot.Tasks
task = heap.Pop ();
}
- if (task == null && !should_halt) {
+ if ((tasks_queued >= max_tasks || task == null) && !should_halt) {
wait.WaitOne ();
- continue;
+ if (task == null)
+ continue;
}
- task.Execute ();
+ Interlocked.Increment (ref tasks_queued);
+ ThreadPool.QueueUserWorkItem ((o) => {
+ task.Execute ();
+ Log.DebugFormat ("Finished task {0}", task);
+ Interlocked.Decrement (ref tasks_queued);
+ wait.Set ();
+ });
}
}
@@ -125,39 +138,4 @@ namespace FSpot.Tasks
#endregion
}
-
-#region Task
-
- public class WorkerThreadTask<T> : Task<T>
- {
- public delegate T TaskHandler ();
-
- TaskHandler handler;
-
- public WorkerThreadTask (TaskHandler h) {
- this.handler = h;
- }
-
- protected override void InnerSchedule ()
- {
- WorkerThreadTaskScheduler.Instance.Schedule (this);
- }
-
- protected override void InnerUnschedule ()
- {
- WorkerThreadTaskScheduler.Instance.Unschedule (this);
- }
-
- protected override void InnerReschedule ()
- {
- WorkerThreadTaskScheduler.Instance.Reschedule (this);
- }
-
- protected override T InnerExecute () {
- return handler ();
- }
- }
-
-#endregion
-
}
diff --git a/src/ThumbnailCommand.cs b/src/ThumbnailCommand.cs
index 95f0bfc..7e3d14e 100644
--- a/src/ThumbnailCommand.cs
+++ b/src/ThumbnailCommand.cs
@@ -46,9 +46,7 @@ public class ThumbnailCommand {
{
var loader = App.Instance.Loaders.RequestLoader (item);
var preview_task = loader.FindBestPreview (256, 256);
- var task = new WorkerThreadTask<bool> (() => { preview_task.Result.Dispose (); return false; }) {
- Priority = TaskPriority.Background
- };
+ var task = new Task<bool> (() => { preview_task.Result.Dispose (); return false; }, TaskPriority.Background);
preview_task.ContinueWith (task);
}
}
diff --git a/src/Widgets/Filmstrip.cs b/src/Widgets/Filmstrip.cs
index 97ec661..55c69df 100644
--- a/src/Widgets/Filmstrip.cs
+++ b/src/Widgets/Filmstrip.cs
@@ -608,7 +608,7 @@ namespace FSpot.Widgets
var loader = App.Instance.Loaders.RequestLoader ((selection.Collection [i]).DefaultVersion);
var preview_task = loader.FindBestPreview (ThumbSize, ThumbSize);
- var task = new WorkerThreadTask<bool> (() => {
+ var task = new Task<bool> (() => {
Pixbuf pixbuf = preview_task.Result;
if (SquaredThumbs) {
current = PixbufUtils.IconFromPixbuf (pixbuf, ThumbSize);
@@ -622,9 +622,7 @@ namespace FSpot.Widgets
QueueDraw ();
});
return false;
- }) {
- Priority = TaskPriority.Interactive
- };
+ }, TaskPriority.Interactive);
preview_task.ContinueWith (task);
} else {
current = thumb_cache.Get (uri).ShallowCopy ();
diff --git a/src/Widgets/IconView.cs b/src/Widgets/IconView.cs
index c590d3b..ada64a9 100644
--- a/src/Widgets/IconView.cs
+++ b/src/Widgets/IconView.cs
@@ -845,7 +845,7 @@ namespace FSpot.Widgets
{
var loader = App.Instance.Loaders.RequestLoader (item.DefaultVersion);
var preview_task = loader.FindBestPreview (ThumbnailWidth, ThumbnailHeight);
- var task = new WorkerThreadTask<bool> (() => {
+ var task = new Task<bool> (() => {
if (preview_task.Result == null)
return false;
ThreadAssist.ProxyToMain (() => {
@@ -854,9 +854,7 @@ namespace FSpot.Widgets
}
});
return false;
- }) {
- Priority = TaskPriority.Interactive
- };
+ }, TaskPriority.Interactive);
preview_task.ContinueWith (task);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]