백엔드 개발 C#.Net 튜토리얼 C# WinForm 다중 스레드 개발 (3) Control.Invoke

C# WinForm 다중 스레드 개발 (3) Control.Invoke

Feb 20, 2017 am 10:51 AM
c#

원본주소 : 링크를 열려면 클릭하세요

[Abstract]본 글에서는 C#을 소개합니다. WinForm 다중 스레드 개발을 위한 Control.Invoke 및 자세한 샘플 코드가 참조용으로 제공됩니다.

아래에서는 Windows Form에서 Invoke를 사용할 때 주의해야 할 멀티스레딩 문제에 대해 소개하겠습니다. 소프트웨어.

먼저 멀티스레딩을 사용하면 어떤 작업을 고려해야 할까요? 일반적인 규칙은 사용자와의 상호 작용을 담당하는 스레드(이하 UI 스레드)가 원활하게 유지되어야 한다는 것입니다. UI 스레드에서 호출된 API가 30밀리초 이상의 차단 시간(예: 울트라 액세스)을 유발할 수 있는 경우 CD-ROM, 원격 호출 등과 같은 느린 주변 장치) 멀티스레딩 사용을 고려해야 합니다. 왜 30밀리초인가? 30밀리초라는 개념은 사람의 눈으로 감지할 수 있는 지연으로, 영화의 한 프레임 길이와 거의 동일하며 최대 100밀리초를 초과해서는 안 됩니다.

둘째, 가장 편리하고 간단한 멀티스레딩은 스레드 풀을 이용하는 것입니다. 스레드 풀의 스레드를 통해 코드를 실행하는 가장 쉬운 방법은 비동기 대리자 호출을 사용하는 것입니다. 대리자 호출은 일반적으로 동기식으로 완료되므로 호출할 메서드를 스레드 풀에 대기시켜 처리를 기다리면 프로그램 흐름이 즉시 호출자(여기서는 UI 스레드)로 반환됩니다. , 통화 따라서 막힘이 없습니다.

다음 예제를 보면 스레드 풀을 사용하여 코드를 비동기적으로 실행하는 것이 그리 복잡하지 않다는 것을 알 수 있습니다. 여기서는 System.Windows.Forms.MethodInvoker 대리자를 사용하여 비동기 호출을 수행합니다. MethodInvoker 대리자는 메서드 매개 변수를 허용하지 않습니다. 비동기적으로 실행되는 메서드에 매개 변수를 전달해야 하는 경우 다른 대리자를 사용하거나 직접 정의해야 합니다.


private void StartSomeWorkFromUIThread () {
    // 我们要做的工作相对UI线程而言台慢了,用下面的方法异步进行处理
    MethodInvoker mi = new MethodInvoker(RunsOnWorkerThread);//这是入口方法
    mi.BeginInvoke(null, null); // 这样就不会阻塞
}

// 缓慢的工作在此方法内进行处理,使用线程池里的线程
private void RunsOnWorkerThread() {
    DoSomethingSlow();
}
로그인 후 복사


위 방법을 요약하면 UI 스레드의 경우 실제로는 다음과 같습니다. 1. 전화 걸기, 2. 돌아오기 즉시, 특정 작업은 UI 스레드가 차단되지 않도록 프로세스가 무시됩니다. 이 접근 방식은 중요하므로 아래에서 자세히 다루겠습니다. 위의 방법 외에도 스레드 풀을 사용하는 다른 방법이 있습니다. 물론, 만족스러우면 자신만의 스레드를 생성할 수도 있습니다.

第三,在Windows Form中使用多线程的,最重要的一条注意事项是,除了创建控件的线程以外,绝对不要在任何其他线程里面调用控件的成员(只有极个别情况例外),也就是说控件属于创建它的线程,不能从其他线程里面访问。这一条适用于所有从System.Windows.Forms.Control派生的控件(因此可以说是几乎所有控件),包括Form控件本身也是。举一反三,我们很容易得出这样的结论,控件的子控件必须由创建控件的线程来创建,比如一个表单上的按钮,比如由创建表单的线程来创建,因此,一个窗口中的所有控件实际上都活在同一个线程之中。在实际编程时,大多数的软件的做法都是让同一线程负责全部的控件,这就是我们所说的UI线程。看下面的例子:


// 这是由UI线程定义的Label控件
private Label lblStatus;
// 以下方法不在UI线程上执行
private void RunsOnWorkerThread() {
    DoSomethingSlow();
    lblStatus.Text = "Finished!";    // 这是错的
}
로그인 후 복사


我们要特别提醒大家,很多人刚开始的时候都会使用以上的方法来访问不在同一个线程里的控件(包括笔者本人),而且在1.0版.Net 框架上似乎没有发现问题,但是这根本就是错的,更糟糕的是,程序员在这里不会得到任何错误提示,一开始就上当受骗,之后会莫明其妙地发现其他错误,这就是Windows Form多线程编程的痛苦所在。笔者试过花很多时间来Debug自己写的Splash窗口突然消失的问题,结果还是失败了:笔者在软件的引导过程中,用另外一个线程里创建了一个Splash窗口来显示欢迎信息,然后尝试把主线程里引导的状态直接写入到Splash窗口上的控件中,开始还OK,可是过一会Splash窗口就莫明其妙消失了。

理解了这一点,我们应该留意到,有时候即使没有用System.Threading.Thread来显式创建一个线程,我们也可能因为使用了异步委托的BeginInvoke方法来隐式创建了线程(从线程池里),在这种线程里也同样不能调用UI线程所创建的控件的成员。

第四,由于上述限制,我们可能会感到很不方便,的确,当我们利用一个新创建的线程来执行某些花时间的运算时,怎样知道运算进度如何并通过UI反映给用户呢?解决方法很多!比如熟悉多线程编程的用户很快会想到,我们采用一些低级的同步方法,工作者线程把状态保存到一个同步对象中,让UI线程轮询(Polling)该对象并反馈给用户就可以了。不过,这还是挺麻烦的,实际上不用这样做,Control类(及其派生类)对象有一个Invoke方法很特别,这是少数几个不受线程限制的成员之一。我们前面说到,绝对不要在任何其他线程里面调用非本线程创建的控件的成员时,也说了“只有极个别情况例外”,这个Invoke方法就是极个别情况之一----Invoke方法可以从任何线程里面调用。下面我们来讲解Invoke方法。

Invoke方法的参数很简单,一个委托,一个参数表(可选),而Invoke方法的主要功能就是帮助你在UI线程(即创建控件的线程)上调用委托所指定的方法。Invoke方法首先检查发出调用的线程(即当前线程)是不是UI线程,如果是,直接执行委托指向的方法,如果不是,它将切换到UI线程,然后执行委托指向的方法。不管当前线程是不是UI线程,Invoke都阻塞直到委托指向的方法执行完毕,然后切换回发出调用的线程(如果需要的话),返回。注意,使用Invoke方法时,UI线程不能处于阻塞状态。以下MSDN里关于Invoke方法的说明:


“控件上有四种方法可以安全地从任何线程进行调用:Invoke、BeginInvoke、EndInvoke 和 CreateGraphics。对于所有其他方法调用,则应使用调用 (invoke) 方法之一封送对控件的线程的调用。
委托可以是 EventHandler 的实例,在此情况下,发送方参数将包含此控件,而事件参数将包含 EventArgs.Empty。委托还可以是 MethodInvoker 的实例或采用 void 参数列表的其他任何委托。调用 EventHandler 或 MethodInvoker 委托比调用其他类型的委托速度更快。”
로그인 후 복사


好了,说完Invoke,顺便说说BeginInvoke,毫无疑问这是Invoke的异步版本(Invoke是同步完成的),不过大家不要和上面的System.Windows.Forms.MethodInvoker委托中的BeginInvoke混淆,两者都是利用不同线程来完成工作,但是控件的BeginInvoke方法总是使用UI线程,而其他的异步委托调用方法则是利用线程池里的线程。相对Invoke而言,使用BeginInvoke稍稍麻烦一点,但还是那句话,异步比同步效果好,尽管复杂些。比如同步方法可能出现这样一种死锁情况:工作者线程通过Invoke同步调用UI线程里的方法时会阻塞,而万一UI线程正在等待工作者线程做某件事时怎么办?因此,能够使用异步方法时应尽量使用异步方法。

下面我们利用所学到的知识来改写上面那个简单的例子:


// 这是由UI线程定义的Label控件
private Label lblStatus;
// 以下方法不在UI线程上执行
private void RunsOnWorkerThread() {
    DoSomethingSlow();
    // Do UI update on UI thread
    object[] pList = { this, System.EventArgs.Empty };
    lblStatus.BeginInvoke(
      new System.EventHandler(UpdateUI), pList);
}
// 切换回UI线程执行的入口
private void UpdateUI(object o, System.EventArgs e) {
    //现在没问题了,使用Invoke使得线程总是回到UI线程,所以我们可以放心大胆地调用控件的成员了
    lblStatus.Text = "Finished!";
}
로그인 후 복사

第五,关于多线程编程还要考虑线程之间的同步问题、死锁和争用条件,有关这类问题的文章很多,我们就不赘述了

 以上就是C# WinForm多线程开发(三) Control.Invoke 的内容,更多相关内容请关注PHP中文网(www.php.cn)!


본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 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 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

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

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

C#을 사용한 Active Directory C#을 사용한 Active Directory Sep 03, 2024 pm 03:33 PM

C#을 사용한 Active Directory 가이드. 여기에서는 소개와 구문 및 예제와 함께 C#에서 Active Directory가 작동하는 방식에 대해 설명합니다.

C#의 난수 생성기 C#의 난수 생성기 Sep 03, 2024 pm 03:34 PM

C#의 난수 생성기 가이드입니다. 여기서는 난수 생성기의 작동 방식, 의사 난수 및 보안 숫자의 개념에 대해 설명합니다.

C# 데이터 그리드 보기 C# 데이터 그리드 보기 Sep 03, 2024 pm 03:32 PM

C# 데이터 그리드 뷰 가이드. 여기서는 SQL 데이터베이스 또는 Excel 파일에서 데이터 그리드 보기를 로드하고 내보내는 방법에 대한 예를 설명합니다.

C#의 액세스 한정자 C#의 액세스 한정자 Sep 03, 2024 pm 03:24 PM

C#의 액세스 수정자에 대한 안내입니다. 예제 및 출력과 함께 C#의 액세스 한정자의 소개 유형에 대해 논의했습니다.

C# 직렬화 C# 직렬화 Sep 03, 2024 pm 03:30 PM

C# 직렬화 가이드. 여기에서는 C# 직렬화 개체의 소개, 단계, 작업 및 예제를 각각 논의합니다.

C#의 패턴 C#의 패턴 Sep 03, 2024 pm 03:33 PM

C#의 패턴 가이드. 여기에서는 예제 및 코드 구현과 함께 C#의 패턴 소개 및 상위 3가지 유형에 대해 설명합니다.

C#의 소수 C#의 소수 Sep 03, 2024 pm 03:35 PM

C#의 소수 가이드. 여기서는 코드 구현과 함께 C#의 소수에 대한 소개와 예를 논의합니다.

C#의 팩토리얼 C#의 팩토리얼 Sep 03, 2024 pm 03:34 PM

C#의 팩토리얼 가이드입니다. 여기서는 다양한 예제 및 코드 구현과 함께 C#의 계승에 대한 소개를 논의합니다.

See all articles