C\#사용자 정의 정시 구성 요 소 를 실현 하 는 방법

본 고 는.NET Framework 에서 제공 하 는 몇 개의 Timer 와 는 다른 사용자 정의 타이머 구성 요 소 를 보 여 줍 니 다.먼저 이 구성 요소 의 개발 배경 을 말 해 보 니 현재 하 는 일 은 시간 과 떨 어 질 수 없다 는 것 을 알 게 되 었 습 니 다.시간 에 맞 춰 임 무 를 수행 하고 모든 것 을 시간 에 맞 춰 무엇 을 하 는 지,일정 시간 마다 어떤 일 을 하 는 지'시간'이라는 단 어 를 떠 날 수 없습니다.다 중 스 레 드 를 사용 해 야 한 다 는 것 은 잘 알려 져 있 습 니 다.다 중 스 레 드 에 관 한 여러 편의 글 에서 주기 적 인 조작 을 할 때 Timer 를 사용 하 는 것 이 좋 습 니 다.물론 이 Timer 는 Threading.Timer 일 것 입 니 다.WinForm 컨트롤 에 있 는 Timer 가 아 닙 니 다.하지만 저 는 제 응용 프로그램 에서 Timer 가 수 요 를 만족 시 키 지 못 한다 고 생각 합 니 다.
1.Timer 는 작업 과 작업 사이 에 만 일정 시간 간격 으로 작업 할 수 있 습 니 다.다음 그림 입 니 다.

그러나 내 가 필요 한 것 은 이번 임무 가 시 작 될 때 부터 다음 임무 가 시 작 될 때 까지 는 동등한 시간 이 고 다음 그림 과 같다.

이런 상황 에서 타 이 머 는 수 요 를 만족 시 킬 수 없다.
2.Timer 의 시간 간격 은 일반적으로 정 해 져 있 지만 임 무 를 수행 할 때마다 휴면 시간 을 바 꾸 려 면 Timer 의 Change 방법 을 사용 해 야 합 니 다.
3.Timer 의 휴면 시간 은 성형 을 통 해 휴면 의 밀리초 수 를 확정 하 는 것 이 아니 라 하나의 TimeSpan 으로 확정 하 는 것 이다.매일 몇 시간 이나 시간 당 몇 분 에 한 번 씩 수행 하 는 임무 에 있어 서도 완전히 편리 하 게 사용 할 수 없다.
위의 세 가지 에 대해 필 자 는 타이머 에 대해 패 키 징 을 했 습 니 다.Timer 를 버 렸 습 니까?아니면 기 존의 Thread 로 되 돌아 가 중복 시간 을 설명 하 는 패턴 문자열 을 정의 하여 TimeSpan 을 계산 하여 Thread 의 Sleep()방법 으로 휴면 을 했 습 니까?전체 구성 요소 의 아 날로 그 를 보 여 줍 니 다.

마지막 으로 시간 계산 에 관 한 두 가지 유형 입 니 다.두 대 리 는 두 가지 임무 방법 에 대한 의뢰 입 니 다.기본 적 인 BaseCycleMission 은 주기 적 인 임무 의 축적 으로 ICycle 인 터 페 이 스 를 실 현 했 습 니 다.주로 임무 스 레 드 에 대한 조작(시작,정지 등)을 실 시 했 습 니 다.그의 두 가지 유형 을 계승 하 는 것 중 하 나 는 상기 첫 번 째 점 에서 제 가 그 수 요 를 묘사 한 것 입 니 다.기 존 Timer 와 유사 한 기능그들 은 각자 다른 의뢰 를 사용한다.Mission Manager 는 모든 주기 작업 에 대한 관리 일 뿐 특정한 작업 을 통일 적 으로 시작 하거나 중단 합 니 다.
시간 계산 모듈
그럼 먼저 정 의 된 문자열 모드 를 소개 하 겠 습 니 다.현재 만 나 는 주 기 는 두 가지 모델 이 있 는데,
하 나 는 얼마 에 한 번 씩 임 무 를 수행 해 야 하 는 지 하 는 것 이다.이것 은 가장 일반적인 주기 형식 이다.5 분 마다 예 를 들 면 완전한 형식 은'-99-99-99-99-99:05'이 고'-99'는 부족 하 다 는 뜻 이다.물론 다른 약자 모델 도 있다.
다른 하 나 는 언제 한 번 도 임 무 를 수행 하지 않 았 다 는 것 이다.예 를 들 어 낮 12 시가 되 지 않 은 것 을 예 로 들 면 완전한 형식 은'ff-ff-ff 12:ff:ff'이 고'ff'는 기본 적 인 형식 이다.물론'FF'를 사용 할 수도 있 고 여기에 다른 약자 모델 도 있다.
모든 문자열 의 패턴 은 다음 표 와 같 습 니 다.
 
***시간 마다
시간 당***
온전 하 다
ff-ff-ff ff:ff:ff 또는
ff-ff-ff ff:ff:ff
-99--99--99 -99:-99:-99
날짜 부분
ff-ff-ff 또는
ff-ff-ff
-99--99--99
시간 부분
ff:ff:ff 또는
ff:ff:ff
-99:-99:-99
시간 약자
ff:ff 또는
ff:ff
-99:-99
그러면 시간 계산 모듈 의 처리 절 차 는 해당 하 는 패턴 문자열 을 지정 한 것 입 니 다.TimePointConverter 는 정규 표현 식 을 통 해 해당 하 는 패턴 을 일치 시 키 고 일치 하 는 년 월 일 시 분 초 각 값 을 되 돌려 결 과 를 얻 은 후에 SleepTimeProvider 를 사용 하여 스 레 드 가 휴면 할 시간 을 계산 합 니 다.다음은 두 가지 종류의 부분 코드 를 보 여 드 리 겠 습 니 다.

public class TimePointConverter
{
//    
private int[] DateTimeFixBuilder(string timeStr)
{
int[] result = null;
string[] dtArray = timeStr.Split();
string[] dateArray = dtArray[0].Split('-');
string[] timeArray = dtArray[1].Split(':');

uint year,month,date;
uint hour, minute, second; 
uint.TryParse(dateArray[0], out year);
uint.TryParse(dateArray[1], out month);
uint.TryParse(dateArray[2], out date);

uint.TryParse(timeArray[0], out hour);
uint.TryParse(timeArray[1], out minute);
uint.TryParse(timeArray[2], out second);

//return InnerFixBuilder(year, month, date, hour, minute, second);
result = new int[] { (int)year, (int)month, (int)date, (int)hour, (int)minute, (int)second };
return result;
}
//    
}

public class SleepTimeProvider
{
//    
public TimeSpan InnerFixBuilder(uint year, uint month, uint date, uint hour, uint minute, uint second)
{
uint[] uintTimeArray = new uint[6] { year, month, date, hour, minute, second };
int[] intNowArray = new int[6] 
{ 
DateTime.Now.Year,DateTime.Now.Month,DateTime.Now.Day,
DateTime.Now.Hour,DateTime.Now.Minute,DateTime.Now.Second 
};
int[] intTimeArray = new int[6];
intTimeArray[0] = uintTimeArray[0] == 0 ? -DateTime.Now.Year : (int)uintTimeArray[0];
for (int i = 1; i < uintTimeArray.Length; i++)
{
intTimeArray[i] = intTimeArray[i - 1] < 0 && uintTimeArray[i] == 0 ?
-intNowArray[i] : (int)uintTimeArray[i];
}
DateTime goalTime = new DateTime(Math.Abs(intTimeArray[0]),
Math.Abs(intTimeArray[1]),
Math.Abs(intTimeArray[2]),
Math.Abs(intTimeArray[3]),
Math.Abs(intTimeArray[4]),
Math.Abs(intTimeArray[5]));
if (goalTime < DateTime.Now)
{
int max = -1;
for (int i = intTimeArray.Length - 1; i >= 0; i--)
{
if (intTimeArray[i] < 0 && i > max)
{
max = i;
intTimeArray[i]--;
}
intTimeArray[i] = Math.Abs(intTimeArray[i]);
}
goalTime = new DateTime(Math.Abs(intTimeArray[0]),
Math.Abs(intTimeArray[1]),
Math.Abs(intTimeArray[2]),
Math.Abs(intTimeArray[3]),
Math.Abs(intTimeArray[4]),
Math.Abs(intTimeArray[5]));
}
return goalTime - DateTime.Now;
}
//    
}

스 레 드 호출 모듈
스 레 드 호출 모듈 은 작업 수행 의 핵심 부분 입 니 다.Mission Entiy 는 스 레 드 작업 에 대한 패 키 징 으로 주로 시작,정지,일시 정지 등 작업 을 책임 집 니 다.Thread 는 백 스테이지 스 레 드 를 사용 하고 스 레 드 를 조작 할 때 도 몇 가지 판단 을 많이 합 니 다.예 를 들 어 그 작업 을 일시 정지 하 는 정 의 는 다음 과 같다.

public bool Pause()
{
if (actionThread == null) return false;
if (actionThread.ThreadState == (System.Threading.ThreadState.Running | ThreadState.Background) ||
actionThread.ThreadState == (System.Threading.ThreadState.WaitSleepJoin | ThreadState.Background))
{
actionThread.Suspend();
return true;
}
return false;
}

CycleMission 은 진정한 퀘 스 트 캐리어 입 니 다.그 안에 똑 같이 스 레 드 에 대한 조작 이 있 지만 시간 처 리 를 추 가 했 습 니 다.가장 핵심 적 인 것 은 스 레 드 를 Buildmain Action 방법 입 니 다.이 방법 은 휴면 할 시간 을 계산 하여 스 레 드 를 휴면 시 키 고 시간 이 되면 적당 한 방법 으로 의뢰 하 는 것 입 니 다.

public class BaseCycleMission:ICycleMission
{
//    
protected void BuildMainAction(string normalCycle, string overTimeCycle, object overTimeDelegate, bool isSleepBefore,bool isInclude)
{
mainAction = () =>
{
TimeSpan sleepTime=TimeSpan.MinValue;
bool result = true;
TimePointConvert.CircleType type ;
#region     
if (isSleepBefore)
{
type = TimePointConvert.Default.PraseType(normalCycle); 
if (type == TimePointConvert.CircleType.Interval)
sleepTime = SleepTimeProvider.Defult.InnerIntervalBuilder(
TimePointConvert.Default.ConvertCircle(normalCycle));
else
sleepTime = SleepTimeProvider.Defult.InnerFixBuilder(
TimePointConvert.Default.ConvertCircle(normalCycle));
if (sleepTime.TotalMilliseconds > 0)
Thread.Sleep(sleepTime);
}
#endregion
while (true)
{
#region     
if (isInclude)
{
if (result)
{
type = TimePointConvert.Default.PraseType(normalCycle); 
type = TimePointConvert.Default.PraseType(overTimeCycle); 
sleepTime = type == TimePointConvert.CircleType.Interval ?
SleepTimeProvider.Defult.InnerIntervalBuilder(
TimePointConvert.Default.ConvertCircle(overTimeCycle)) :
SleepTimeProvider.Defult.InnerFixBuilder(
TimePointConvert.Default.ConvertCircle(overTimeCycle));
}
}
#endregion

#region     

if(overTimeDelegate is OverTimeCycleDelegate)
result = (overTimeDelegate as OverTimeCycleDelegate).Invoke();
else
{
(overTimeDelegate as CycleDelegate).Invoke();
result = true;
}
#endregion

#region     
if (!isInclude)
{
if (result)
{

type = TimePointConvert.Default.PraseType(normalCycle);


sleepTime = type == TimePointConvert.CircleType.Interval ?
SleepTimeProvider.Defult.InnerIntervalBuilder(
TimePointConvert.Default.ConvertCircle(normalCycle)) :
SleepTimeProvider.Defult.InnerFixBuilder(
TimePointConvert.Default.ConvertCircle(normalCycle));
}
else
{
type = TimePointConvert.Default.PraseType(overTimeCycle);

sleepTime = type == TimePointConvert.CircleType.Interval ?
SleepTimeProvider.Defult.InnerIntervalBuilder(
TimePointConvert.Default.ConvertCircle(overTimeCycle)) :
SleepTimeProvider.Defult.InnerFixBuilder(
TimePointConvert.Default.ConvertCircle(overTimeCycle));
}
}
#endregion

if (sleepTime.TotalMilliseconds > 0)
Thread.Sleep(sleepTime);
}
};
}
//    
}

물론 호출 은 이 방법 을 호출 하 는 것 이 아 닙 니 다.호출 은 두 가지 exceptCycleMission 과 IncludeCycleMission 을 호출 하 는 것 입 니 다.각각 작업 수행 시간 은 주기 에 포함 되 지 않 고 주기 에 포함 되 지 않 습 니 다.
관리자 부분
관리 자 는 주로 사전 집합 입 니 다.ICycle Mission 과 문자열 의 사전 집합 입 니 다.집합 에 있 는 모든 요소 에 대한 작업 이 포함 되 어 있 습 니 다.추가,삭제,실행,복구,일시 정지,정지.삭제 와 증 가 를 제외 하고 아래 와 같은 방법 이 포함 되 어 있 습 니 다.

RunAllMission()
RunAllIncludeCycleMission()
RunAllExceptCycleMission()
RunMissionAmong(params string[] missionNames)
RunMissionExcept(params string[] missionNames)

하지만 이 방법 들 에는 모두 CallAction 이라는 방법 이 사용 되 어 있다.

private void CallAction(IEnumerable<ICycleMission> missionCollection,Action method)
{
if (missionCollection == null || method == null||missionCollection.Count()==0) return;

foreach (ICycleMission item in missionCollection)
{
method.Method.Invoke(item, null);
}
}

예 를 들 어 RunAll Excepticy cleMission()방법 에서 다음 과 같이 호출 합 니 다.

public void RunAllExceptCycleMission()
{
CallAction(this.Values.Where(c => c is ExceptCycleMission), BaseCycleMission.Default.RunMission);
}

관심 이 있 는 친 구 는 본 논문 에서 말 한 인 스 턴 스 코드 를 테스트 해 볼 수 있 습 니 다.적지 않 은 수확 이 있 을 것 이 라 고 믿 습 니 다!

좋은 웹페이지 즐겨찾기