찾다
백엔드 개발C#.Net 튜토리얼C#의 타이머 사용 및 재진입 문제 해결에 대한 자세한 설명

이 글에서는 C#에서 Timer를 사용하고 재진입 문제를 해결하는 방법에 대한 관련 지식을 주로 소개합니다. 참고할만한 가치가 아주 좋습니다.

서문

오랜만에 오픈한 라이브라이터입니다. 정말 오랫동안 블로그를 쓰지 않았습니다. 더 이상 고민하지 않고 이 블로그의 주제인 타이머로 바로 넘어가겠습니다. 제가 이 글을 쓰는 이유는 며칠 전에 친구의 초대를 받아 "해커" 가젯을 만들었는데, 기능이 매우 간단해서 클립보드의 내용을 자동으로 가져온 다음 이메일을 보내야 합니다. Timer를 사용하여 클립보드의 내용을 반복합니다. 그러나 이메일 전송 기능으로 인해 C#을 사용하는 SmtpClient는 이전에 이메일 전송과 유사한 기능을 작성한 적이 없습니다. NetEase를 사용할 수 있었는데 지금은 무슨 일이 일어났는지 모르겠어서 포기해야 했습니다. Timer를 사용하다가 이전에는 생각하지 못했던 문제, 즉 재진입 문제에 직면하게 되었습니다.

소개

우선 타이머에 대해 간단히 소개하겠습니다. 여기서 언급하는 타이머는 이름에서 알 수 있듯이 System.Timers.timer를 의미합니다. 지정된 간격으로. 공식 소개는 여기에 있으며 발췌 내용은 다음과 같습니다.

Timer 구성 요소는 애플리케이션에서 Elapsed 이벤트가 발생하는 주기적인 간격을 지정할 수 있는 서버 기반 타이머입니다. 그런 다음 이 이벤트를 처리하여 일반 처리를 제공할 수 있습니다. 예를 들어, 하루 24시간, 일주일 내내 실행되어야 하는 중요한 서버가 있다고 가정해 보겠습니다. 타이머를 사용하여 주기적으로 서버를 확인하고 시스템이 실행되고 있는지 확인하는 서비스를 만들 수 있습니다. 시스템이 응답하지 않으면 서비스는 서버를 다시 시작하거나 관리자에게 알릴 수 있습니다. 서버 기반 타이머는 다중 스레드 환경에서 보조 스레드와 함께 사용하도록 설계되었습니다. 서버 타이머는 스레드 간에 이동하여 발생한 Elapsed 이벤트를 처리할 수 있으므로 Windows 타이머보다 더 정확한 시간에 이벤트가 발생할 수 있습니다.

다른 타이머와의 차이점을 알고 싶으시면 여기를 읽어보세요. 자세한 소개가 있어서 더 이상 말하지 않겠습니다(사실 이렇게 많은 타이머가 있는지 몰랐습니다) 더). 그렇다면 이 타이머를 사용하면 어떤 이점이 있을까요? 주로 .NET 스레드 풀을 통해 구현되고, 가볍고, 정확한 타이밍을 가지며, 애플리케이션과 메시지에 대한 특별한 요구 사항이 없기 때문입니다.

사용법

다음은 이 Timer의 사용 방법에 대한 간략한 소개입니다. 실제로는 Microsoft에서 제공하는 예제를 사용하여 테스트해 보겠습니다. . 코드로 바로 이동:

//Timer不要声明成局部变量,否则会被GC回收
 private static System.Timers.Timer aTimer;
 public static void Main()
 {
 //实例化Timer类,设置间隔时间为10000毫秒; 
 aTimer = new System.Timers.Timer(10000);
 //注册计时器的事件
 aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
 //设置时间间隔为2秒(2000毫秒),覆盖构造函数设置的间隔
 aTimer.Interval = 2000;
 //设置是执行一次(false)还是一直执行(true),默认为true
 aTimer.AutoReset = true;
 //开始计时
 aTimer.Enabled = true;
 Console.WriteLine("按任意键退出程序。");
 Console.ReadLine();
 }
 //指定Timer触发的事件
 private static void OnTimedEvent(object source, ElapsedEventArgs e)
 {
 Console.WriteLine("触发的事件发生在: {0}", e.SignalTime);
 }

실행 결과는 다음과 같습니다. 타이밍이 매우 정확합니다.

/*
按任意键退出程序。
触发的事件发生在: 2014/12/26 星期五 23:08:51
触发的事件发生在: 2014/12/26 星期五 23:08:53
触发的事件发生在: 2014/12/26 星期五 23:08:55
触发的事件发生在: 2014/12/26 星期五 23:08:57
触发的事件发生在: 2014/12/26 星期五 23:08:59
*/

재진입 문제 재현 및 분석

재입장이란 무엇인가요? 어디로 들어가나요? 이는 다중 스레드 프로그래밍에 대한 개념입니다. 프로그램에서 여러 스레드가 동시에 실행될 때 동일한 메서드가 여러 프로세스에서 동시에 호출될 수 있습니다. 이 메소드에 스레드가 아닌 안전 코드가 있는 경우 메소드 재진입으로 인해 데이터 불일치가 발생합니다. 타이머 방법 재진입은 다중 스레드 타이머를 사용하는 것을 의미합니다. 한 타이머의 처리가 완료되기 전에 시간이 다 되면 다른 타이머가 계속해서 처리 방법에 들어갑니다. 다음은 재진입 문제의 발생을 보여줍니다(재현이 좋지 않을 수 있지만 문제를 간략하게 설명할 수도 있음).

//用来造成线程同步问题的静态成员
 private static int outPut = 1;
 //次数,timer没调一次方法自增1
 private static int num = 0;
 private static System.Timers.Timer timer = new System.Timers.Timer();
 public static void Main()
 {
 timer.Interval = 1000;
 timer.Elapsed += TimersTimerHandler;
 timer.Start();
 Console.WriteLine("按任意键退出程序。");
 Console.ReadLine();
 }
 /// <summary>
 /// System.Timers.Timer的回调方法
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="args"></param>
 private static void TimersTimerHandler(object sender, EventArgs args)
 {
 int t = ++num;
 Console.WriteLine(string.Format("线程{0}输出:{1}, 输出时间:{2}", t, outPut.ToString(),DateTime.Now));
 System.Threading.Thread.Sleep(2000);
 outPut++;
 Console.WriteLine(string.Format("线程{0}自增1后输出:{1},输出时间:{2}", t, outPut.ToString(),DateTime.Now));
 }

다음은 출력 결과를 보여줍니다.

위 출력이 이상하다고 느끼시나요? 먼저 스레드 1의 출력은 1이므로 문제가 없습니다. 그러면 2초 후에 스레드 1이 1씩 증가하여 2를 출력합니다. . 중간에 여전히 문제가 있는 이유는 무엇입니까? 더 이상한 점은 스레드 2의 출력이 처음에는 1이었다가 1씩 증가한 후 3이 되었다는 것입니다! 사실 이것은 재진입으로 인해 발생하는 문제입니다. 걱정하지 마세요. 몇 가지 분석을 통해 이유를 알아낼 수 있습니다.

먼저 타이머가 타이밍을 시작한 후 스레드 1 실행 방법이 시작됩니다. 스레드 1이 처음으로 출력되면 스레드 1은 2초 동안 휴면 상태가 됩니다. 설정된 타이밍 간격은 1초입니다. 스레드 1이 1초 동안 휴면한 후 타이머는 스레드 2의 실행 방법을 엽니다. 스레드 2는 스레드 1이 실행 중인지 휴면 중인지 상관하지 않으므로 이때 스레드 2의 출력도 1입니다. , 왜냐하면 쓰레드 1은 아직 휴면상태에 있어서 스스로 증가하지 않았기 때문입니다. 그리고 또 1초가 지났습니다. 이때 두 개의 이벤트가 동시에 발생했습니다. 스레드 1이 휴면 상태를 통과하고 자동 증가 출력이 2가 되었습니다. 타이머도 동시에 스레드 3의 출력을 시작했습니다. 스레드 1이 자동 증가한 후 값 2였습니다. 1초가 더 지나면 스레드 2가 휴면 상태를 통과했습니다. 이전 출력은 이미 2였으므로 자동 증가 후의 출력은 3이었습니다. 또 1초가 지났습니다... 거의 기절할 뻔했습니다. 내가 표현하고 싶은 것은 아마도 하나의 Timer가 시작한 스레드 처리가 완료되지 않았는데, 시간이 다 되면 다른 Timer가 계속해서 처리 방법을 입력한다는 것입니다.

그럼 이 문제를 어떻게 해결해야 할까요? 세 가지 해결책이 있습니다. 다양한 시나리오에 적응하기 위해 하나씩 살펴보겠습니다. 그러나 우리는 여전히 더 안전한 마지막 방법을 권장합니다.

재진입 문제 해결

1、使用lock(Object)的方法来防止重入,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就等待执行,适用重入很少出现的场景(具体也没研究过,可能比较占内存吧)。

代码跟上面差不多,在触发的方法中加入lock,这样当线程2进入触发的方法中,发现已经被锁,会等待锁中的代码处理完在执行,代码如下:

private static object locko = new object(); 
 /// <summary>
 /// System.Timers.Timer的回调方法
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="args"></param>
 private static void TimersTimerHandler(object sender, EventArgs args)
 {
 int t = ++num; 
 lock (locko)
 { Console.WriteLine(string.Format("线程{0}输出:{1}, 输出时间:{2}", t, outPut.ToString(), DateTime.Now)); 
 System.Threading.Thread.Sleep(2000); 
 outPut++; Console.WriteLine(string.Format("线程{0}自增1后输出:{1},输出时间:{2}", t, outPut.ToString(), DateTime.Now)); } }

 执行结果:

 2、设置一个标志,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就放弃(注意这里是放弃,而不是等待哦,看看执行结果就明白啥意思了)执行,适用重入经常出现的场景。代码如下:

 private static int inTimer = 0; 
 /// <summary>
 /// System.Timers.Timer的回调方法
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="args"></param>
 private static void TimersTimerHandler(object sender, EventArgs args)
 {
 int t = ++num;
 if (inTimer == 0)
 {
 inTimer = 1;
 Console.WriteLine(string.Format("线程{0}输出:{1}, 输出时间:{2}", t, outPut.ToString(), DateTime.Now));
 System.Threading.Thread.Sleep(2000);
 outPut++;
 Console.WriteLine(string.Format("线程{0}自增1后输出:{1},输出时间:{2}", t, outPut.ToString(), DateTime.Now));
 inTimer = 0;
 }
 }

执行结果:

3、在多线程下给inTimer赋值不够安全,Interlocked.Exchange提供了一种轻量级的线程安全的给对象赋值的方法(感觉比较高上大,也是比较推荐的一种方法),执行结果与方法2一样,也是放弃执行。Interlocked.Exchange用法参考这里。

private static int inTimer = 0; 
 /// <summary>
 /// System.Timers.Timer的回调方法
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="args"></param>
 private static void TimersTimerHandler(object sender, EventArgs args)
 {
 int t = ++num;
 if (Interlocked.Exchange(ref inTimer, 1) == 0)
 {
 Console.WriteLine(string.Format("线程{0}输出:{1}, 输出时间:{2}", t, outPut.ToString(), DateTime.Now));
 System.Threading.Thread.Sleep(2000);
 outPut++;
 Console.WriteLine(string.Format("线程{0}自增1后输出:{1},输出时间:{2}", t, outPut.ToString(), DateTime.Now));
 Interlocked.Exchange(ref inTimer, 0); 
 }
 }

执行结果:

总结

终于码完字了,真心不容易啊。写博客是个挺耗精力的事情,真心佩服那些大牛们笔耕不辍,致敬!在这里稍微总结一下,timer是一个使用挺简单的类,拿来即用,这里主要总结了使用timer时重入问题的解决,以前也没思考过这个问题,解决方案也挺简单,在这里列出了三种,不知道还有没有其他的方式。这里的解决方案同时也适用多线程的重入问题。

위 내용은 C#의 타이머 사용 및 재진입 문제 해결에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
다양한 .NET 언어로서 C# : 응용 프로그램 및 예제다양한 .NET 언어로서 C# : 응용 프로그램 및 예제Apr 26, 2025 am 12:26 AM

C#은 엔터프라이즈 레벨 애플리케이션, 게임 개발, 모바일 응용 프로그램 및 웹 개발에서 널리 사용됩니다. 1) 엔터프라이즈 레벨 애플리케이션에서 C#은 종종 asp.netcore가 webapi를 개발하는 데 사용됩니다. 2) 게임 개발에서 C#은 Unity 엔진과 결합되어 역할 제어 및 기타 기능을 실현합니다. 3) C#은 코드 유연성 및 응용 프로그램 성능을 향상시키기 위해 다형성 및 비동기 프로그래밍을 지원합니다.

웹, 데스크탑 및 모바일 개발 용 C# .net웹, 데스크탑 및 모바일 개발 용 C# .netApr 25, 2025 am 12:01 AM

C# 및 .NET은 웹, 데스크탑 및 모바일 개발에 적합합니다. 1) 웹 개발에서 ASP.NETCORE는 크로스 플랫폼 개발을 지원합니다. 2) 데스크탑 개발은 WPF 및 Winforms를 사용하여 다양한 요구에 적합합니다. 3) 모바일 개발은 Xamarin을 통한 크로스 플랫폼 응용 프로그램을 실현합니다.

C# .NET Ecosystem : 프레임 워크, 라이브러리 및 도구C# .NET Ecosystem : 프레임 워크, 라이브러리 및 도구Apr 24, 2025 am 12:02 AM

C#.NET 생태계는 개발자가 응용 프로그램을 효율적으로 구축 할 수 있도록 풍부한 프레임 워크 및 라이브러리를 제공합니다. 1.asp.netCore는 고성능 웹 애플리케이션을 구축하는 데 사용되며 2.entityFrameworkCore는 데이터베이스 작업에 사용됩니다. 이러한 도구의 사용 및 모범 사례를 이해함으로써 개발자는 응용 프로그램의 품질과 성능을 향상시킬 수 있습니다.

C# .NET 애플리케이션 배포 Azure/AWS : 단계별 안내서C# .NET 애플리케이션 배포 Azure/AWS : 단계별 안내서Apr 23, 2025 am 12:06 AM

C# .NET 앱을 Azure 또는 AWS에 배포하는 방법은 무엇입니까? 답은 Azureappservice와 Awelasticbeanstalk를 사용하는 것입니다. 1. Azure에서 Azureappservice 및 AzurePipelines를 사용하여 배포를 자동화하십시오. 2. AWS에서 Amazon Elasticbeanstalk 및 Awslambda를 사용하여 배포 및 서버리스 컴퓨팅을 구현하십시오.

C# .net : 강력한 프로그래밍 언어 소개C# .net : 강력한 프로그래밍 언어 소개Apr 22, 2025 am 12:04 AM

C#과 .NET의 조합은 개발자에게 강력한 프로그래밍 환경을 제공합니다. 1) C#은 다형성 및 비동기 프로그래밍을 지원합니다. 2) .net은 크로스 플랫폼 기능과 동시 처리 메커니즘을 제공하여 데스크탑, 웹 및 모바일 애플리케이션 개발에 널리 사용됩니다.

.NET 프레임 워크 대 C#: 용어 디코딩.NET 프레임 워크 대 C#: 용어 디코딩Apr 21, 2025 am 12:05 AM

.NETFramework는 소프트웨어 프레임 워크이며 C#은 프로그래밍 언어입니다. 1..netframework는 데스크탑, 웹 및 모바일 애플리케이션 개발을 지원하는 라이브러리 및 서비스를 제공합니다. 2.C#은 .NETFramework 용으로 설계되었으며 최신 프로그래밍 기능을 지원합니다. 3..NetFramework는 CLR을 통해 코드 실행을 관리하고 C# 코드는 IL로 컴파일되어 CLR에 의해 실행됩니다. 4. .NETFramework를 사용하여 응용 프로그램을 신속하게 개발하면 C#은 LINQ와 같은 고급 기능을 제공합니다. 5. 일반적인 오류에는 유형 변환 및 비동기 프로그래밍 교착 상태가 포함됩니다. 디버깅을 위해서는 VisualStudio 도구가 필요합니다.

Demystifying C# .net : 초보자를위한 개요Demystifying C# .net : 초보자를위한 개요Apr 20, 2025 am 12:11 AM

C#은 Microsoft에서 개발 한 최신 객체 지향 프로그래밍 언어이며 .NET은 Microsoft가 제공하는 개발 프레임 워크입니다. C#은 C의 성능과 Java의 단순성을 결합하며 다양한 응용 프로그램을 구축하는 데 적합합니다. .NET 프레임 워크는 여러 언어를 지원하고 쓰레기 수집 메커니즘을 제공하며 메모리 관리를 단순화합니다.

C# 및 .NET 런타임 : 함께 작동하는 방법C# 및 .NET 런타임 : 함께 작동하는 방법Apr 19, 2025 am 12:04 AM

C# 및 .NET 런타임은 개발자가 효율적이고 강력하며 크로스 플랫폼 개발 기능을 강화하기 위해 긴밀히 협력합니다. 1) C#은 .NET 프레임 워크와 완벽하게 통합하도록 설계된 유형 안전 및 객체 지향 프로그래밍 언어입니다. 2) .NET 런타임은 C# 코드 실행을 관리하고, 쓰레기 수집, 유형 안전 및 기타 서비스를 제공하며, 효율적이고 크로스 플랫폼 운영을 보장합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

ZendStudio 13.5.1 맥

ZendStudio 13.5.1 맥

강력한 PHP 통합 개발 환경

맨티스BT

맨티스BT

Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

PhpStorm 맥 버전

PhpStorm 맥 버전

최신(2018.2.1) 전문 PHP 통합 개발 도구