线程池虽然好用,但限制也不少:

(1)总觉得默认的 MaxThread 小了一点,每次使用都要手工调大= =

(2)任务不能等待完成

(3)任务一旦加入不能取消,甚至不知道是正在排队/正在执行/执行完毕

(4)最恶心的一点,全是 MTAThread,好多COM都不能用。ClipBoard、WebBrowser ...

实在不能忍了,自己写了个“任务池”,模拟线程池的功能。不同点有:

(1)没有数量上限,新进的任务不需要排队(但任务太多可能影响系统性能)

(2)任务的创建和开始可以分开,也可以创建时就开始。

(3)任务可等待

(4)任务可强制取消,虽然非常非常非常非常非常不建议这么做,这可能造成不可预知的问题

(5)可以选择任务线程的 ApartmentState (MTA / STA / Unknown = 无所谓)

相同点在于:

(1)保证(近乎绝对的)线程安全,逻辑上没有线程不安全的地方

(2)线程可重用

不足之处在于:

(1)还是应该添加限制线程数目的功能,避免对系统性能造成太大影响

(2)任务应该支持“尝试取消”操作

(3)有些 TTask 类里的字段应该对用户只读,但语法上实在做不到= =(没有 friend 关键字)

Version 1.0

 using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Mime;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading; // ReSharper Disable InconsistentNaming namespace Efficiency.Core { //+ delegate TTaskDelegate
public delegate void TTaskDelegate(TTask task, object param); //+ class TTask
public class TTask { public readonly AutoResetEvent Event = new AutoResetEvent(false);
public readonly ApartmentState ApartmentState; public readonly TTaskDelegate Callback;
public readonly object Param; public Thread Thread { get; set; } //-- .ctor()
public TTask(TTaskDelegate callback, object param, ApartmentState state)
{
this.ApartmentState = state;
this.Param = param;
this.Callback = callback;
} public int Status = ;
// 0: Working...
// 1: Marked Finished
// 2: Marked Force Exited
public bool IsFinished => (this.Status != ); public bool Wait(int timeout = -) => this.Event.WaitOne(timeout); //-- void ForceExit()
public void ForceExit()
{
if (Interlocked.CompareExchange(ref this.Status, , ) != ) return;
try {
this.Thread.Abort();
}
catch {
// Ignored
}
} //-- void ForceExit(out Exception)
public bool ForceExit(out Exception exception)
{
exception = null;
if (Interlocked.CompareExchange(ref this.Status, , ) != ) return true;
try {
this.Thread.Abort();
return true;
}
catch(Exception ex) {
exception = ex;
return false;
}
}
} // class TTask //+ class TTaskPool
public static class TTaskPool { //+ class TTaskPool.TTaskThreadContext
private class TTaskThreadContext {
public static volatile int CanExit = ; public readonly AutoResetEvent WaitEvent = new AutoResetEvent(false);
public readonly Queue<Thread> ThreadQueue;
public TTask Task; //-- .ctor()
public TTaskThreadContext(Queue<Thread> threadQueue, TTask task)
{
this.ThreadQueue = threadQueue;
this.Task = task;
} } // class TTaskPool.TTaskThreadContext private static readonly Queue<Thread> m_STAQueue = new Queue<Thread>();
private static readonly ReaderWriterLock m_STARWLock = new ReaderWriterLock();
private static readonly Dictionary<Thread, TTaskThreadContext> m_STAContext =
new Dictionary<Thread, TTaskThreadContext>(); private static readonly Queue<Thread> m_MTAQueue = new Queue<Thread>();
private static readonly ReaderWriterLock m_MTARWLock = new ReaderWriterLock();
private static readonly Dictionary<Thread, TTaskThreadContext> m_MTAContext =
new Dictionary<Thread, TTaskThreadContext>(); private static int s_PeakSTATaskCount = ;
public static int PeakSTATaskCount => s_PeakSTATaskCount; private static int s_PeakMTATaskCount = ;
public static int PeakMTATaskCount => s_PeakMTATaskCount; public static int PeakTaskCount => PeakMTATaskCount + PeakSTATaskCount; //-- TTask CreateTask(TTaskDelegate, object)
[MethodImpl(0x100)]
public static TTask CreateTask(
TTaskDelegate callback,
object param = null,
ApartmentState state = ApartmentState.Unknown)
{
if (callback == null) {
throw new ArgumentNullException(nameof(callback));
}
return new TTask(callback, param, state);
} //-- bool TryInsertTask(TTask, ThreadQueue<Thread>, Dictionary<Thread, TTaskThreadContext>, ReaderWriterLock)
[MethodImpl(0x100)]
private static bool TryInsertTask(
TTask task,
Queue<Thread> queue,
Dictionary<Thread, TTaskThreadContext> dict,
ReaderWriterLock rwlock,
ApartmentState state,
bool force)
{
Thread thread = null;
TTaskThreadContext context;
bool isNew;
lock (queue) {
if (queue.Count == ) {
if (! force) return false;
isNew = true;
}
else {
thread = queue.Dequeue();
isNew = false;
}
} if (isNew) {
thread = new Thread(TTaskThreadRoutine);
thread.SetApartmentState(state);
thread.IsBackground = true;
if (state == ApartmentState.STA)
Interlocked.Increment(ref s_PeakSTATaskCount);
else
Interlocked.Increment(ref s_PeakMTATaskCount); context = new TTaskThreadContext(queue, task);
rwlock.AcquireWriterLock(-);
dict.Add(thread, context);
rwlock.ReleaseWriterLock();
thread.Start(context);
}
else {
rwlock.AcquireReaderLock(-);
context = dict[thread];
rwlock.ReleaseReaderLock();
context.Task = task;
context.WaitEvent.Set();
} return true;
} //-- void InsertTask(TTask)
public static void InsertTask(TTask task)
{
if (task == null) {
throw new ArgumentNullException(nameof(task));
} switch (task.ApartmentState) {
case (ApartmentState.STA):
TryInsertTask(task, m_STAQueue, m_STAContext, m_STARWLock, ApartmentState.STA, true);
break; case (ApartmentState.MTA):
TryInsertTask(task, m_MTAQueue, m_MTAContext, m_MTARWLock, ApartmentState.MTA, true);
break; default:
if (TryInsertTask(task, m_MTAQueue, m_MTAContext, m_MTARWLock, ApartmentState.MTA, false)) return;
if (TryInsertTask(task, m_STAQueue, m_STAContext, m_STARWLock, ApartmentState.STA, false)) return;
TryInsertTask(task, m_MTAQueue, m_MTAContext, m_MTARWLock, ApartmentState.MTA, true);
break;
} } //-- TTask CreateInsertTask(STATaskDelegate, object, ApartmentState)
[MethodImpl(0x100)]
public static TTask CreateInsertTask(
TTaskDelegate callback,
object param = null,
ApartmentState state = ApartmentState.Unknown)
{
if (callback == null) {
throw new ArgumentNullException(nameof(callback));
}
TTask task = new TTask(callback, param, state);
InsertTask(task);
return task;
} //-- void TTaskThreadRoutine(object)
private static void TTaskThreadRoutine(object threadContext)
{
TTaskThreadContext context = (TTaskThreadContext)threadContext;
Thread thisThread = Thread.CurrentThread;
while (true) {
if (TTaskThreadContext.CanExit != ) return;
thisThread.Priority = ThreadPriority.Normal; TTask task = context.Task;
task.Callback.Invoke(task, task.Param);
task.Thread = thisThread;
thisThread.IsBackground = true; task.Event.Set();
if (Interlocked.CompareExchange(ref task.Status, , ) == ) {
try {
thisThread.Abort();
}
catch {
// Ignored
}
}
if (TTaskThreadContext.CanExit != ) return; lock (context.ThreadQueue) {
context.ThreadQueue.Enqueue(thisThread);
}
context.WaitEvent.WaitOne(-);
}
} } // class TTaskPool } // namespace Efficiency.Core

[.NET] 自己实现任务池(模仿线程池)的更多相关文章

  1. Python 线程池的原理和实现及subprocess模块

    最近由于项目需要一个与linux shell交互的多线程程序,需要用python实现,之前从没接触过python,这次匆匆忙忙的使用python,发现python确实语法非常简单,功能非常强大,因为自 ...

  2. 简单理解设计模式——享元模式-线程池-任务(tesk)

    前面在写到多线程的文章的时候,一直想写一篇关于线程池等一系列的文章,做一下记录,本篇博客记录一下设计模式中享元模式的设计思想,以及使用享元模式的实现案例——线程池,以及线程池的简化版——任务(tesk ...

  3. 模仿.Net ThreadPool的线程池控件

    http://www.2ccc.com/btdown.asp?articleid=5953 ftp://download:S3cirpYW3DoR@www.2ccc.com/vcl/system/20 ...

  4. Nginx 引入线程池,提升 9 倍性能

    转载:http://blog.csdn.net/wuliusir/article/details/50760357 众所周知,NGINX 采用异步.事件驱动的方式处理连接.意味着无需对每个请求创建专门 ...

  5. java中线程池的使用方法

    1 引入线程池的原因 由于线程的生命周期中包括创建.就绪.运行.阻塞.销毁阶段,当我们待处理的任务数目较小时,我们可以自己创建几个线程来处理相应的任务,但当有大量的任务时,由于创建.销毁线程需要很大的 ...

  6. Java 并发编程——Executor框架和线程池原理

    Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...

  7. 探究ElasticSearch中的线程池实现

    探究ElasticSearch中的线程池实现 ElasticSearch里面各种操作都是基于线程池+回调实现的,所以这篇文章记录一下java.util.concurrent涉及线程池实现和Elasti ...

  8. j.u.c系列(01) ---初探ThreadPoolExecutor线程池

    写在前面 之前探索tomcat7启动的过程中,使用了线程池(ThreadPoolExecutor)的技术 public void createExecutor() { internalExecutor ...

  9. Java 并发编程——Executor框架和线程池原理

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

随机推荐

  1. css3中webkit-box的用法

    转自:http://www.frontopen.com/288.html 1.之前要实现横列的web布局,通常就是float或者display:inline-block; 但是都不能做到真正的流体布局 ...

  2. phpMyAdmin - 错误 您应升级到 MySQL 5.5.0 或更高版本,解决办法。。。

    折腾自己的个人网站,装了个数据库管理工具,遇到您应升级到 MySQL 5.5.0 或更高版本... 采用降级phpmyadmin版本的方法解决了: 查找phpmyadmin/libraries/com ...

  3. 恢复 root 本地无权限 Access denied for user 'root'@'localhost' (using password: NO)

    调试远程的时候,覆盖了本地的权限.导致  本地无法登陆系统表.  远程连接上mysql  执行以下命令恢复. 恢复root  本地管理权限  使用空密码 grant all on *.* to roo ...

  4. recovery编译问题汇总

    1.修改支持USB大容量存储 (1).首先需要查看手机lun位置 手机链接电脑,打开cmd命令行,依次输入以下命令: adb shell find /sys -name "lun" ...

  5. low-rank 的相关求解方法 (CODE) Low-Rank Matrix Recovery and Completion via Convex Optimization

    (CODE) Low-Rank Matrix Recovery and Completion via Convex Optimization 这个是来自http://blog.sina.com.cn/ ...

  6. seleniu+python+chrome的调试

    1.下载chrome,下载chrome driver,下载地址:http://code.google.com/p/chromedriver/downloads/list 2.安装chrome,默认路径 ...

  7. TCP协议与UDP协议的区别

    TCP协议与UDP协议的区别(转) 首先咱们弄清楚,TCP协议和UCP协议与TCP/IP协议的联系,很多人犯糊涂了,一直都是说TCP/IP协议与UDP协议的区别,我觉得这是没有从本质上弄清楚网络通信! ...

  8. 2013年最棒的4个PHP框架

    PHP 框架可以帮你编写简洁可重用的代码,遵循 MVC 模式,确保应用逻辑和展现分离.有很多很多的框架各有千秋,有的性能好,有的文档全,还有的提供大量的内建功能等等. 这里我们罗列的 2013 年最好 ...

  9. 开启GZIP(转)

    因为在做一个项目,项目里面服务器主要提供数据,但是数据多了文件就大了,比较浪费流量和时间,我们便用Gzip来处理.我在本机上是apache,服务器上是IIS6.0,用的是php,那么我就在这里分享一下 ...

  10. 【转】关于Oracle将小于1的数字to_char后丢掉0的解决办法

    SQL代码如下: select rtrim(to_char(0.11, 'fm9990.99'), '.') from dual; 其中0.11为需要to_char的数字fm去掉字符串前面的空格999 ...