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

(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. react-native执行 npm install cl.exe找不到 的问题

    最近在学习react-native,昨天在尝试某个demo时,执行 npm instal, 总是遇到 cl.exe文件找不到,最开始以为Microsoft Visual C++ 2015 Redist ...

  2. hdoj 1576

    //1Y真是爽啊 题意:要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1).  分析:根据题意a=b*x   a=m ...

  3. 使用AjaxPro实现无刷新更新数据

    需求 在一个页面动态无刷新的更新后台得到的数据.要想无刷新的更新数据,需要使用Javascript能够获取后台返回的数据,然后通过第三方Javascript库(JQuery等)动态更新web页面DOM ...

  4. mac 端口被占用及kill端口

    在本地部署 Web 应用时我有遇到过某网络端口已经被其他程序占用的情况,这时候就需要先退出占用该端口的进程,我们可以通过“终端”来实现结束占用某特定端口的进程 1.打开终端,使用如下命令: lsof ...

  5. Linux——【转】gcc编译与gdb调试简要步骤

    原文:gcc编译与gdb调试简要步骤 一.Linux程序gcc编译步骤: Gcc编译过程主要的4个阶段: l 预处理阶段,完成宏定义和include文件展开等工作:(.i) l 根据编译参数进行不同程 ...

  6. Jupyter notebook 配置目录

    默认打开Jupyter notebook,工作目录是C:\Users\Username,这里面有很多其它与Jupyter notebook无关的文件,也很有用,不能看着烦就删掉,所以需要修改Jupyt ...

  7. 在 ASP.NET 中创建数据访问和业务逻辑层(转)

    .NET Framework 4 当在 ASP.NET 中处理数据时,可从使用通用软件模式中受益.其中一种模式是将数据访问代码与控制数据访问或提供其他业务规则的业务逻辑代码分开.在此模式中,这两个层均 ...

  8. MiniTwitter记住密码等功能实现

    一.SharedPreferences的用法:(相关实现功能的只是了解) 由于SharedPreferences是一个接口,而且在这个接口里没有提供写入数据和读取数据的能力.但它是通过其Editor接 ...

  9. android-自定义控件之液位指示器

    由于安卓应用很广泛,在工业中也常有一些应用,比如可以用安卓来去工业中的一些数据进行实现的监测,显示,同时可以做一些自动化控制,当然在这里,我不是做这些自动化控制方面的研究,只是做一个控件,液位指示,其 ...

  10. php 字符串转数组

    $str = "你好吗"; function str($str) {     $length = mb_strlen($str);     for ($i=0; $i<$le ...