[.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并发 ...
随机推荐
- vba单元格背景色
cells(i,j).interior.color=5287936 green =255 red
- Shell中的空格和引号
空格对于linux的shell是一种很典型的分隔符,所以给变量赋值的时候中间不能够有空格.而单引号和双引号,都是为了解决中间有空格的问题.比如string1=this is a string,这样执行 ...
- EF6 CodeFirst+Repository+Ninject+MVC4+EasyUI实践(八)
前言 本篇幅将对系统的菜单管理模块进行说明,系统的菜单采用树形结构,这样可以更好地方便层级设计和查看.本示例将说明如何通过EntityFramework读取递归的菜单树形结构,以及结合EasyUI的t ...
- Java面试常见各种概念区别比较
Hashtable 和 HashMap之间的区别 Hashtable是继承了Dictionary,是线程安全的.HashMap实现了Map接口,不是线程安全的.HashMap是Hashtable的轻量 ...
- 日常小测:颜色 && Hackerrank Unique_colors
题目传送门:https://www.hackerrank.com/challenges/unique-colors 感谢hzq大神找来的这道题. 考虑点分治(毕竟是路经统计),对于每一个颜色,它的贡献 ...
- Java集合类学习笔记(Set集合)
Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入. HashSet类的特点: 不能保证元素的排列顺序,顺 ...
- Fragment的onResume
需求:Fragment每次由不可见到可见时的回调. 可能最先想到的是onResume方法,实际使用中Fragment的onResume调用时机与其Activity一致,因此类似与viewPager搭配 ...
- Matlab_Graphics(1)_2D
1.Add title ,axis Lables, and Legend to Graph: x=linspace(-*pi,2pi,); y1=sin(x); y2=cos(x); figure p ...
- css 中content内容特殊形状
用到的一些特殊字符和图标html代码<div class="cross"></div>css代码.cross{ width: 20px; hei ...
- NSLOG打印不全的问题
#ifdef DEBUG #define NSLog(FORMAT, ...) fprintf(stderr, "%s:%zd\t%s\n", [[[NSString string ...