diff --git a/Apewer/CronAttribute.cs b/Apewer/CronAttribute.cs
index fcd9581..0f5adcc 100644
--- a/Apewer/CronAttribute.cs
+++ b/Apewer/CronAttribute.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.Design;
using System.Reflection;
using System.Text;
using System.Threading;
@@ -8,10 +9,12 @@ namespace Apewer
{
/// Cron 特性,默认间隔为 60 秒。
- [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class CronAttribute : Attribute, IToJson
{
+ #region attribute
+
private int _mode = 0;
private int _seconds = 0;
private CronCycle _cycle = CronCycle.Once;
@@ -51,7 +54,23 @@ namespace Apewer
return json;
}
- #region Payload
+ ///
+ public override string ToString()
+ {
+ if (_type != null)
+ {
+ if (_mode == 1) return $"Type = {_type.FullName}, Seconds = {_seconds}";
+ if (_mode == 2) return $"Type = {_type.FullName}, Cycle = {_cycle}, Seconds = {_seconds}";
+ }
+ return base.ToString();
+ }
+
+ #endregion
+
+ #region payload
+
+ /// 执行 Cron 的类。
+ public Type Type { get => _type; }
// 传入。
Type _type = null;
@@ -61,13 +80,25 @@ namespace Apewer
// 实时。
Thread _thread = null;
bool _alive = false;
+ bool _break = false;
+ /// 运行当前 Cron。
void Run()
{
- _alive = true;
- _thread = new Thread(Payload);
- _thread.IsBackground = false;
- _thread.Start();
+ if (_alive) return;
+ if (_type == null) return;
+
+ _break = false;
+ UsePool(pool =>
+ {
+ if (pool.ContainsKey(_type)) return;
+ pool.Add(_type, this);
+
+ _alive = true;
+ _thread = new Thread(Payload);
+ _thread.IsBackground = false;
+ _thread.Start();
+ });
}
// 当前进程睡眠。
@@ -83,11 +114,11 @@ namespace Apewer
var next = DateTime.MinValue;
while (true)
{
- if (_break) break;
+ if (_break || _break_all) break;
if (_now < next)
{
Sleep();
- if (_break) break;
+ if (_break || _break_all) break;
continue;
}
@@ -102,9 +133,9 @@ namespace Apewer
var next = DateTime.Now.AddSeconds(_seconds);
while (_now < next)
{
- if (_break) break;
+ if (_break || _break_all) break;
Sleep();
- if (_break) break;
+ if (_break || _break_all) break;
}
Invoke();
}
@@ -134,11 +165,11 @@ namespace Apewer
// 启动循环。
while (true)
{
- if (_break) break;
+ if (_break || _break_all) break;
if (_now < next)
{
Sleep();
- if (_break) break;
+ if (_break || _break_all) break;
continue;
}
@@ -164,7 +195,13 @@ namespace Apewer
}
}
- _alive = false;
+ UsePool(pool =>
+ {
+ if (pool.ContainsKey(_type)) pool.Remove(_type);
+
+ _break = false;
+ _alive = false;
+ });
}
void Invoke()
@@ -188,13 +225,52 @@ namespace Apewer
#endregion
- #region CronInvoker
+ #region pool
+
+ static Dictionary _pool = new Dictionary();
+
+ static void UsePool(Action> callback)
+ {
+ if (callback == null) throw new ArgumentNullException(nameof(callback));
+ lock (_pool)
+ {
+ callback.Invoke(_pool);
+ }
+ }
- static object _start = new object();
- static CronAttribute[] _crons = null;
- static bool _break = false;
+ static T UsePool(Func, T> callback)
+ {
+ if (callback == null) throw new ArgumentNullException(nameof(callback));
+ lock (_pool)
+ {
+ return callback.Invoke(_pool);
+ }
+ }
+
+ #endregion
+
+ #region invoker
+
+ static bool _break_all = false;
static DateTime _now;
- static int _crons_alive = 0;
+
+ /// 获取状态,指示打断 Cron 循环。
+ public static bool Breaking { get => _break_all; }
+
+ /// 正在运行的 Cron 数量。
+ public static int AliveCount { get => CountAlive(UsePool(pool => pool.Values)); }
+
+ /// 获取正在运行的 Cron 数量。
+ ///
+ static int CountAlive(IEnumerable crons)
+ {
+ var alive = 0;
+ foreach (var cron in crons)
+ {
+ if (cron._alive) alive += 1;
+ }
+ return alive;
+ }
static CronAttribute[] Init(IEnumerable assemblies, Logger logger, bool logEvent)
{
@@ -226,6 +302,14 @@ namespace Apewer
return array;
}
+ /// 启动指定的 Cron。
+ ///
+ public static void Start(CronAttribute cron)
+ {
+ if (cron == null) throw new ArgumentNullException(nameof(cron));
+ cron.Run();
+ }
+
/// 开始 Cron 调用(阻塞当前线程)。
/// 包含 Cron 的程序集,不指定此参数时将在 AppDomain 中搜索。
/// 日志记录程序,不指定此参数时将使用 Logger.Default。
@@ -239,71 +323,122 @@ namespace Apewer
public static void Start(IEnumerable assemblies = null, Logger logger = null, bool logEvent = true)
{
if (logger == null) logger = Logger.Default;
- lock (_start)
+
+ // 设置控制台事件。
+ Console.CancelKeyPress += (s, e) =>
{
- // 初始化。
- _now = DateTime.Now;
- _crons = Init(assemblies, logger, logEvent);
- if (_crons.Length < 1)
- {
- logger.Error(nameof(CronAttribute), "没有找到带有 Cron 特性的类型。");
- return;
- }
+ _break_all = true;
+ e.Cancel = true;
+ };
+
+ // 初始化。
+ _now = DateTime.Now;
+ var crons = Init(assemblies, logger, logEvent);
+ if (crons.Length > 0)
+ {
+ logger.Text(nameof(CronAttribute), "Crons started。");
- // 启动线程。
- _crons_alive = _crons.Length;
- Console.CancelKeyPress += (s, e) =>
- {
- _break = true;
- e.Cancel = true;
- };
- logger.Text(nameof(CronAttribute), $"启动 {_crons.Length} 个 Cron 线程。");
- foreach (var cron in _crons) cron.Run();
+ // 启动 Cron。
+ foreach (var cron in crons) Start(cron);
- // 监视退出状态。
+ // 等待 Cron 退出。
while (true)
{
Thread.Sleep(100);
_now = DateTime.Now;
- var alive = 0;
- for (var i = 0; i < _crons.Length; i++) if (_crons[i]._alive) alive += 1;
- if (alive < 1) break;
- _crons_alive = alive;
+ if (AliveCount < 1) break;
}
- logger.Text(nameof(CronAttribute), "所有 Cron 已结束。");
+
}
+ logger.Text(nameof(CronAttribute), "Crons ended。");
}
- /// 打断正在执行的 Cron。
- public static void Abort()
+ /// 打断指定的 Cron。
+ ///
+ public static void Abort(Type type)
{
- var crons = _crons;
- if (crons != null)
+ if (type == null) throw new ArgumentNullException(nameof(type));
+
+ UsePool(pool =>
{
- foreach (var cron in crons)
+ if (pool.TryGetValue(type, out var cron))
{
- if (cron == null) continue;
try { cron._thread.Abort(); } catch { }
}
- }
+
+ pool.Remove(type);
+ });
+ }
+
+ /// 打断指定的 Cron。
+ ///
+ public static void Abort(object instance)
+ {
+ if (instance == null) throw new ArgumentNullException(nameof(instance));
+
+ if (instance is Type type) Abort(type);
+ else Abort(instance.GetType());
}
- /// 打断 Cron 循环,不打断正在执行的 Cron。
+ /// 打断所有 Cron。
+ public static void Abort()
+ {
+ UsePool(pool =>
+ {
+ foreach (var item in pool)
+ {
+ try
+ {
+ item.Value._thread.Abort();
+ item.Value._alive = false;
+ item.Value._break = false;
+ }
+ catch { }
+ }
+ });
+ }
+
+ /// 打断 Cron 循环,不打断正在执行的 Job。
+ ///
+ public static void Break(Type type)
+ {
+ if (type == null) throw new ArgumentNullException(nameof(type));
+
+ UsePool(pool =>
+ {
+ if (pool.TryGetValue(type, out var cron))
+ {
+ cron._break = true;
+ }
+ });
+ }
+
+ /// 打断 Cron 循环,不打断正在执行的 Job。
+ ///
+ public static void Break(object instance)
+ {
+ if (instance == null) throw new ArgumentNullException(nameof(instance));
+
+ if (instance is Type type) Break(type);
+ else Break(instance.GetType());
+ }
+
+ /// 打断 Cron 循环,不打断正在执行的 Job。
public static void Break()
{
- _break = true;
+ _break_all = true;
}
- /// 打断 Cron 循环并等待 Cron 执行结束。等待指定的时间后打断正在执行的 Cron。
+ /// 打断 Cron 循环并等待 Job 执行结束。等待指定的时间后打断正在执行的 Job。
/// 强制打断前的等待毫秒数,指定为负数时将无限等待。
public static void Break(int timeout)
{
- _break = true;
+ _break_all = true;
const int interval = 100;
if (timeout < 0)
{
- while (_crons_alive > 0) Thread.Sleep(interval);
+ while (AliveCount > 0) Thread.Sleep(interval);
return;
}
else
@@ -311,7 +446,7 @@ namespace Apewer
if (timeout > 0)
{
var remains = timeout;
- while (remains > 0 && _crons_alive > 0)
+ while (remains > 0 && AliveCount > 0)
{
Thread.Sleep(interval);
remains -= interval;
@@ -321,9 +456,6 @@ namespace Apewer
}
}
- /// 获取状态,指示打断 Cron 循环。
- public static bool Breaking { get => _break; }
-
#endregion
}