using System ;
namespace Timer
{
public abstract class Timer
{
public Action< string > LogFunc;
public Action< string > WarnFunc;
public Action< string > ErrorFunc;
public abstract int AddTask ( uint delay, Action< int > taskCB, Action< int > cancelCB, int count = 1 ) ;
public abstract bool DeleteTask ( int tid) ;
public abstract void Reset ( ) ;
protected int tid = 0 ;
protected abstract int GenerateTid ( ) ;
}
}
using System ;
using System. Collections. Concurrent ;
using System. Threading ;
namespace Timer
{
public class TickTimer : Timer
{
class TickTaskPack {
public int tid;
public Action< int > cb;
public TickTaskPack ( int tid, Action< int > cb) {
this . tid = tid;
this . cb = cb;
}
}
private readonly DateTime startDataTime = new DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 , 0 ) ;
private readonly ConcurrentDictionary< int , TickTask> taskDic;
private readonly Thread timerThread;
private readonly bool setHandle;
private readonly ConcurrentQueue< TickTaskPack> packQue;
private const string tidLock = "TickTimer_tidLock" ;
public TickTimer ( int interval = 0 , bool setHandle = true )
{
taskDic = new ConcurrentDictionary< int , TickTask> ( ) ;
this . setHandle = setHandle;
if ( setHandle) {
packQue = new ConcurrentQueue< TickTaskPack> ( ) ;
}
if ( interval != 0 ) {
void StartTick ( ) {
try
{
while ( true ) {
UpdateTask ( ) ;
Thread. Sleep ( interval) ;
}
}
catch ( ThreadAbortException e) {
WarnFunc?. Invoke ( $"Tick Thread Abort: { e } ." ) ;
}
}
timerThread = new Thread ( new ThreadStart ( StartTick) ) ;
timerThread. Start ( ) ;
}
}
public override int AddTask ( uint delay, Action< int > taskCB, Action< int > cancelCB, int count = 1 )
{
int tid = GenerateTid ( ) ;
double startTime = GetUTCMillisecond ( ) ;
double destTime = startTime + delay;
TickTask task = new TickTask ( tid, delay, count, destTime, taskCB, cancelCB, startTime) ;
if ( taskDic. TryAdd ( tid, task) )
{
return tid;
}
else
{
WarnFunc?. Invoke ( $"key: { tid } already exist." ) ;
return - 1 ;
}
}
public override bool DeleteTask ( int tid)
{
if ( taskDic. TryRemove ( tid, out TickTask task) )
{
if ( setHandle&& task. canceCB!= null )
{
packQue. Enqueue ( new TickTaskPack ( tid, task. canceCB) ) ;
}
else {
task. canceCB?. Invoke ( tid) ;
}
return true ;
}
else {
WarnFunc?. Invoke ( $"key: { tid } remove failed." ) ;
return false ;
}
}
public override void Reset ( )
{
if ( ! packQue. IsEmpty) {
WarnFunc?. Invoke ( "Callback Queue is not Empty" ) ;
}
taskDic. Clear ( ) ;
if ( timerThread != null ) {
timerThread. Abort ( ) ;
}
}
public void UpdateTask ( ) {
double nowTime = GetUTCMillisecond ( ) ;
foreach ( var item in taskDic) {
TickTask task = item. Value;
if ( nowTime < task. destTime) {
continue ;
}
++ task. loopIndex;
if ( task. count > 0 ) {
-- task. count;
if ( task. count == 0 )
{
FinishTask ( task. tid) ;
}
else {
task. destTime = task. startTime + task. delay * ( task. loopIndex + 1 ) ;
CallTaskCB ( task. tid, task. taskCB) ;
}
}
else
{
task. destTime = task. startTime + task. delay * ( task. loopIndex + 1 ) ;
CallTaskCB ( task. tid, task. taskCB) ;
}
}
}
public void HandleTask ( ) {
while ( packQue != null && packQue. Count> 0 ) {
if ( packQue. TryDequeue ( out TickTaskPack pack) )
{
pack. cb. Invoke ( pack. tid) ;
}
else {
ErrorFunc?. Invoke ( "packQue Dequeue Data Error." ) ;
}
}
}
void FinishTask ( int tid) {
if ( taskDic. TryRemove ( tid, out TickTask task) )
{
CallTaskCB ( tid, task. taskCB) ;
task. taskCB = null ;
}
else {
WarnFunc?. Invoke ( $"Remove tid: { tid } task in Dic Failed." ) ;
}
}
void CallTaskCB ( int tid, Action< int > taskCB) {
if ( setHandle)
{
packQue. Enqueue ( new TickTaskPack ( tid, taskCB) ) ;
}
else {
taskCB. Invoke ( tid) ;
}
}
private double GetUTCMillisecond ( ) {
TimeSpan ts = DateTime. UtcNow - startDataTime;
return ts. TotalMilliseconds;
}
protected override int GenerateTid ( )
{
lock ( tidLock) {
while ( true ) {
++ tid;
if ( tid == int . MaxValue) {
tid = 0 ;
}
if ( ! taskDic. ContainsKey ( tid) ) {
return tid;
}
}
}
}
class TickTask {
public int tid;
public uint delay;
public int count;
public double destTime;
public Action< int > taskCB;
public Action< int > canceCB;
public double startTime;
public ulong loopIndex;
public TickTask ( int tid, uint delay, int count, double destTime, Action< int > taskCB, Action< int > cancelCB, double startTime)
{
this . tid = tid;
this . delay = delay;
this . count = count;
this . destTime = destTime;
this . taskCB = taskCB;
this . canceCB = cancelCB;
this . startTime = startTime;
this . loopIndex = 0 ;
}
}
}
}
using System ;
using System. Threading. Tasks ;
using Timer ;
namespace ExampleServer
{
class Program
{
static void Main ( string [ ] args)
{
TickTimerExample ( ) ;
Console. ReadKey ( ) ;
}
static void TickTimerExample ( ) {
TickTimer timer = new TickTimer ( 0 , false ) ;
uint intervel = 66 ;
int count = 50 ;
int sum = 0 ;
int taskID = 0 ;
Task. Run ( async ( ) => {
await Task. Delay ( 2000 ) ;
DateTime historyTime = DateTime. UtcNow;
taskID = timer. AddTask (
intervel,
( int tid) => {
DateTime nowTime = DateTime. UtcNow;
TimeSpan ts = nowTime - historyTime;
historyTime = nowTime;
int delta = ( int ) ( ts. TotalMilliseconds - intervel) ;
Console. WriteLine ( $"间隔: { delta } " ) ;
sum += Math. Abs ( delta) ;
Console. WriteLine ( $"tid: { tid } " ) ;
} ,
( int tid) => {
} ,
count
) ;
} ) ;
Task. Run ( async ( ) =>
{
Console. WriteLine ( "Handle Start." ) ;
while ( true ) {
timer. UpdateTask ( ) ;
await Task. Delay ( 2 ) ;
}
} ) ;
while ( true ) {
string ipt = Console. ReadLine ( ) ;
if ( ipt == "calc" )
{
Console. WriteLine ( $"平均间隔: { sum * 1.0 / count } " ) ;
}
else if ( ipt == "del" ) {
timer. DeleteTask ( taskID) ;
}
}
}
}
}
using UnityEngine ;
using System. Collections ;
using PETimer ;
using PEUtils ;
using System ;
public class Example1 : MonoBehaviour {
TickTimer timer;
uint intervel = 66 ;
int count = 50 ;
void Start ( ) {
LogConfig cfg = new LogConfig { loggerType = LoggerType. Unity } ;
PELog. InitSettings ( cfg) ;
timer = new TickTimer ( 10 , true ) {
LogFunc = PELog. Log,
WarnFunc = PELog. Warn,
ErrorFunc = PELog. Error
} ;
}
int sum = 0 ;
int taskID = 0 ;
void Update ( ) {
timer. HandleTask ( ) ;
if ( Input. GetKeyDown ( KeyCode. A) ) {
DateTime historyTime = DateTime. UtcNow;
taskID = timer. AddTask (
intervel,
( int tid) => {
DateTime nowTime = DateTime. UtcNow;
TimeSpan ts = nowTime - historyTime;
historyTime = nowTime;
int delta = ( int ) ( ts. TotalMilliseconds - intervel) ;
PELog. ColorLog ( LogColor. Yellow, $"间隔差: { delta } " ) ;
sum += Math. Abs ( delta) ;
PELog. ColorLog ( LogColor. Magenta, "tid:{0} work." , tid) ;
} ,
( int tid) => {
PELog. ColorLog ( LogColor. Magenta, "tid:{0} cancel." , tid) ;
} ,
count) ;
}
if ( Input. GetKeyDown ( KeyCode. Delete) ) {
timer. DeleteTask ( taskID) ;
}
if ( Input. GetKeyDown ( KeyCode. S) ) {
PELog. ColorLog ( LogColor. Red, "平均间隔:" + sum * 1.0f / count) ;
}
}
}