[.NET] 自己实现任务池(模仿线程池)
线程池虽然好用,但限制也不少:
(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] 自己实现任务池(模仿线程池)的更多相关文章
- Python 线程池的原理和实现及subprocess模块
最近由于项目需要一个与linux shell交互的多线程程序,需要用python实现,之前从没接触过python,这次匆匆忙忙的使用python,发现python确实语法非常简单,功能非常强大,因为自 ...
- 简单理解设计模式——享元模式-线程池-任务(tesk)
前面在写到多线程的文章的时候,一直想写一篇关于线程池等一系列的文章,做一下记录,本篇博客记录一下设计模式中享元模式的设计思想,以及使用享元模式的实现案例——线程池,以及线程池的简化版——任务(tesk ...
- 模仿.Net ThreadPool的线程池控件
http://www.2ccc.com/btdown.asp?articleid=5953 ftp://download:S3cirpYW3DoR@www.2ccc.com/vcl/system/20 ...
- Nginx 引入线程池,提升 9 倍性能
转载:http://blog.csdn.net/wuliusir/article/details/50760357 众所周知,NGINX 采用异步.事件驱动的方式处理连接.意味着无需对每个请求创建专门 ...
- java中线程池的使用方法
1 引入线程池的原因 由于线程的生命周期中包括创建.就绪.运行.阻塞.销毁阶段,当我们待处理的任务数目较小时,我们可以自己创建几个线程来处理相应的任务,但当有大量的任务时,由于创建.销毁线程需要很大的 ...
- Java 并发编程——Executor框架和线程池原理
Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...
- 探究ElasticSearch中的线程池实现
探究ElasticSearch中的线程池实现 ElasticSearch里面各种操作都是基于线程池+回调实现的,所以这篇文章记录一下java.util.concurrent涉及线程池实现和Elasti ...
- j.u.c系列(01) ---初探ThreadPoolExecutor线程池
写在前面 之前探索tomcat7启动的过程中,使用了线程池(ThreadPoolExecutor)的技术 public void createExecutor() { internalExecutor ...
- Java 并发编程——Executor框架和线程池原理
Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...
随机推荐
- css利用padding生成图标
先插入HTML结构: <div class="line-three"></div> <div class="circle"> ...
- .net 附加W3wp进程
步骤:1.鼠标右键点击application项目中的web,找到属性 2.修改web服务器地址(如果使用localhost报错,则http://电脑IP/): 3.在本地iis中找到你部署的网站,点击 ...
- 【DIY】【外壳】木板 & 亚克力 加工
—————————————————————————————————————————————————————————————————————— 一.途径 淘宝 https://item.taobao.c ...
- jquery 巧用json传参
JavaScript代码,巧用JSON传参数function AddComment(content) { var comment = {}; comment.threadId = $("#s ...
- js 简繁体字转换
有些项目需要用到简体和繁体两种字体,在js前台进行转换比较方便而且显示速度没有延时 是一个比较好的解决方案. var _isFT_CS = 0// 简体 var _isFT_CT = 1// 繁体 v ...
- eclipse 字体、背景、自动提示设置
1 字体设置 点击最上面菜单栏的“Window”---“preferences”弹出属性界面 General--- Appearance---Colors and Fronts,找到Java 选择“ ...
- Android Build System
归类一些Android build system 相关的知识. http://elinux.org/Android_Build_System make <local_module> - m ...
- Linux下Gcc生成和使用静态库和动态库详解(转)
一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...
- SpringMVC与MyBatis整合(一)——查询人员列表
从今天开始,一点点的记录做毕设和学习的过程. 寒假才开始接触SpringMVC和MyBatis,之前对框架的概念理解并不到位,也没学过Spring.目前学习起来思路并不很清晰,有些东西我还不能理解,只 ...
- TPCH Benchmark with Impala
1. 生成测试数据在TPC-H的官网http://www.tpc.org/tpch/上下载dbgen工具,生成数据http://www.tpc.org/tpch/spec/tpch_2_17_0.zi ...