Skip to content

Commit

Permalink
Terminate threads from thread pool after idling
Browse files Browse the repository at this point in the history
  • Loading branch information
rpaquay committed Feb 12, 2020
1 parent 1b1c291 commit 3718a00
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 15 deletions.
10 changes: 6 additions & 4 deletions src/Server/Threads/CustomThreadPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,21 @@
using System.Threading;
using VsChromium.Core.Linq;
using VsChromium.Core.Logging;
using VsChromium.Core.Threads;

namespace VsChromium.Server.Threads {
[Export(typeof(ICustomThreadPool))]
public class CustomThreadPool : ICustomThreadPool {
private readonly object _lock = new object();
private readonly ThreadPool _threadPool;

public CustomThreadPool() {
_threadPool = new ThreadPool(10);
[ImportingConstructor]
public CustomThreadPool(IDateTimeProvider dateTimeProvider)
: this(dateTimeProvider, 10) {
}

public CustomThreadPool(int capacity) {
_threadPool = new ThreadPool(capacity);
public CustomThreadPool(IDateTimeProvider dateTimeProvider, int capacity) {
_threadPool = new ThreadPool(dateTimeProvider, capacity);
}

public void RunAsync(Action task) {
Expand Down
42 changes: 33 additions & 9 deletions src/Server/Threads/ThreadObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,52 @@
// found in the LICENSE file.

using System;
using System.Diagnostics;
using System.Threading;
using VsChromium.Core.Logging;
using VsChromium.Core.Threads;

namespace VsChromium.Server.Threads {
public class ThreadObject {
private readonly ThreadPool _threadPool;
private readonly int _id;
private readonly IDateTimeProvider _dateTimeProvider;
private readonly AutoResetEvent _taskAvailable = new AutoResetEvent(false);
private readonly ThreadPool _threadPool;
private Action _currentTask = null;
private Thread _thread;
private readonly object _threadLock = new object();

public ThreadObject(int id, ThreadPool threadPool) {
public ThreadObject(ThreadPool threadPool, int id, IDateTimeProvider dateTimeProvider) {
_dateTimeProvider = dateTimeProvider;
_id = id;
_threadPool = threadPool;
}

private void Loop() {
private void ThreadLoop() {
lock (_threadLock) {
Debug.Assert(_thread != null);
Debug.Assert(Thread.CurrentThread == _thread);
}
while (true) {
_taskAvailable.WaitOne();
bool signaled = _taskAvailable.WaitOne(TimeSpan.FromSeconds(5));
if (!signaled) {
// Exit thread, it's been idle for 5 seconds
break;
}
try {
_currentTask();
}
catch (Exception e) {
// TODO(rpaquay): Do we want to propage the exception here?
Logger.LogError(e, "Error executing task on custom thread pool.");
}
finally {
_currentTask = null;
}
}
// Exit thread
lock (_threadLock) {
_thread = null;
}
}

Expand All @@ -38,11 +58,15 @@ private void Loop() {
/// </summary>
public void RunAsync(Action task) {
if (_thread == null) {
_thread = new Thread(Loop);
_thread.Priority = ThreadPriority.AboveNormal;
_thread.Name = String.Format("CustomThread #{0}", _id);
_thread.IsBackground = true;
_thread.Start();
lock (_threadLock) {
if (_thread == null) {
_thread = new Thread(ThreadLoop);
_thread.Priority = ThreadPriority.AboveNormal;
_thread.Name = String.Format("CustomThread #{0}", _id);
_thread.IsBackground = true;
_thread.Start();
}
}
}

_currentTask = task;
Expand Down
5 changes: 3 additions & 2 deletions src/Server/Threads/ThreadPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using VsChromium.Core.Threads;

namespace VsChromium.Server.Threads {
public class ThreadPool {
Expand All @@ -13,9 +14,9 @@ public class ThreadPool {
private readonly AutoResetEvent _threadReleasedEvent = new AutoResetEvent(false);
private readonly List<ThreadObject> _threads = new List<ThreadObject>();

public ThreadPool(int capacity) {
public ThreadPool(IDateTimeProvider dateTimeProvider, int capacity) {
_capacity = capacity;
_threads.AddRange(Enumerable.Range(0, capacity).Select(i => new ThreadObject(i, this)));
_threads.AddRange(Enumerable.Range(0, capacity).Select(i => new ThreadObject(this, i, dateTimeProvider)));
}

public int Capacity { get { return _capacity; } }
Expand Down

0 comments on commit 3718a00

Please sign in to comment.