C# 스레드 및 위임

17916 단어
카탈로그
  • 관계 정리
  • Thread 객체 생성 스레드
  • 의 이점
  • 단점
  • 적용
  • 샘플 코드 1 단순한 백엔드 서브스레드 처리 콘솔 프로그램
  • 인스턴스 코드 2 UI를 수정해야 하는 하위 스레드 처리 WinFrom 프로그램
  • 실례 코드 3은 대상 파라미터를 통해 서브스레드 결과를 전달하고 얻는다
  • 함수 의뢰 생성 루트
  • 의 이점
  • 단점
  • 사용 현황
  • 예시 코드 1에 매개 변수와 결과 값이 있는 백엔드 서브스레드 처리
  • 인스턴스 코드 2 UI의 하위 스레드 처리를 수정해야 함
  • 기타 고려 사항
  • 주 스레드 정체 처리
  • Thread 객체의 주 정체 처리
  • 함수 의뢰의 혼잡 처리

  • 간단한 백그라운드 처리 모듈 BackgroundWorker
  • 설명
  • 실례 코드


  • 관계 정리
  • C# 스레드 사용은 일반적으로 다음 세 가지 유형을 사용합니다.
  • Thread 객체
  • 함수 의뢰
  • Task Object(검토되지 않음)
  • C#에서 어떤 방식으로든 스레드를 사용하면 의뢰
  • 에 반드시 사용
  • C#에서 스레드에서 위임을 사용하는 것은 비교적 안전하고 일반적인 스레드 간 수정 UI 방식
  • 이다.
  • C#에서 스레드 간 UI 수정은 하위 스레드 생성 방식과 무관하게 사용됩니다.

  • Thread 객체 만들기 스레드
    장점
  • 코드 구조가 간단하고 사용이 비교적 편리하다
  • UI의 논리적 구조를 쉽게 수정할 수 있음
  • 결점
  • 서브라인에 매개 변수 전달 어려움
  • 하위 라인에서 결과를 얻는 데 어려움
  • 적용 상황
  • 주 스레드와 데이터 전달이 필요 없는 경우
  • 하위 스레드 결과가 UI 컨트롤에 직접 나타나는 경우
  • 예제 코드 1: 단순한 백엔드 스레드 처리(콘솔 프로그램)
    public static void main()
    {
        //       (           ,     void     )
        ThreadStart start = new ThreadStart(ConsoleInformation);
        //      
        Thread thread = new Thread(start);
        //    
        thread.Start();
    }
    //            
    public static void ConsoleInformation()
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(string.Format("this is {0} time run in Thread A",i));
            Thread.Sleep(500);
        }
    }

    인스턴스 코드 2: UI의 하위 스레드 처리를 수정해야 함(WinFrom 프로그램)
    /// 
    ///   Thread         
    /// 
    /// 
    private void Base_btn_start_Click(object sender, EventArgs e)
    {
        //UI  ,   ListView   
        UI_lv_content.Items.Clear();
        //       (           ,     void     )
        ThreadStart start = new ThreadStart(UpdateListViewContent);
        //      
        Thread thread = new Thread(start);
        //    
        thread.Start();
    }
    
    //             ,        UI,    UI            
    private void UpdateListViewContent()
    {
        for (int i = 0; i < 5; i++)
        {
            //        ,        ,             
            //this.UI_lv_content.Items.Add(string.Format("this is {0} time in Thread",i));
            //     UI    (     !)
            //Control.CheckForIllegalCrossThreadCalls = false;
            //     ,       ,            
            if (UI_lv_content.InvokeRequired)
                UI_lv_content.Invoke(new Del_UpdateListViewContentParam(Invoke_UpdateListViewContent), i);
            else
                Invoke_UpdateListViewContent();
            }
    }
    //    UI            (     )
    private delegate void Del_UpdateListViewContentParam(int i);
    //    UI       
    private void Invoke_UpdateListViewContent(int i)
    {
        this.UI_lv_content.Items.Add(string.Format("this is {0} time in Thread param", i));
        this.Update();
        //      
        Thread.Sleep(500);
    }

    实例代码3:通过对象参数传递并获取子线程结果

    /// 
    ///              ,  Thread          
    /// 
    ///          Java   Runnable      ,
    ///               ,         Thread                
    private void UI_btn_start4_Click(object sender, EventArgs e)
    {
        CustomParam param=new CustomParam();
        param.X = 12;
        param.Y = 24;
        ThreadStart start = new ThreadStart(param.RunInThread);
        Thread thread = new Thread(start);
        thread.Start();
        //        ,          ,  UI  
        while (thread.IsAlive)
            Application.DoEvents();
        //        ,               
        UI_lv_content.Items.Clear();
        UI_lv_content.Items.Add("finished : " + param.Coordinate);
        UI_lv_content.Update();
    }
    //       (  A)
    private delegate void Del_UpdateListViewContent();

    参数类申明

    public class CustomParam
    {
        private int m_X;
        private int m_Y;
        private string m_coordinate;
        // delegate void Del_UpdateListViewContent()       
        public void RunInThread()
        {
            m_coordinate = string.Format("({0},{1})", X, Y);
            Thread.Sleep(1000);
        }
        //getter setter  
    }

    그러나 이러한 방식으로 UI를 수정하면 UI 컨트롤이 패라메트릭 클래스로 전달되어 구조화된 프로그램 설계가 손상됩니다.
    함수 의뢰 생성 루트
    장점
  • 스레드 조작 권한이 비교적 커서 스레드의 운행 상태를 명확하게 알 수 있다
  • 서브라인의 매개 변수 전달과 매개 변수 획득이 비교적 편리하다
  • 결점
  • UI 수정 시 코드 복잡성 증가
  • 사용 현황
  • 서브스레드 내에서 복잡한 계산을 완성해야 한다. 즉, 서브스레드에 복잡한 파라미터를 제공해야 하는 경우
  • 스레드 결과는 UI에 표시되지 않고 기본 스레드의 다른 곳에서 사용되는 경우
  • 예시 코드 1: 매개 변수와 결과 값이 있는 백엔드 서브스레드 처리
    /// 
    ///            
    /// 
    ///           Thread   ,          。
    ///
    ///         UI     ,              ,        
    /// 
    private void UI_btn_start3_Click(object sender, EventArgs e)
    {
        //UI  
        UI_lv_content.Items.Clear();
        //  UI               
        is_Wait4Main = UI_ck_IsWaitMain2.Checked;
        //      -       UI
        //Del_UpdateListViewContentAsyn del = new Del_UpdateListViewContentAsyn(Invoke_UpdateListViewContentAsyn);
        //      -      UI;
        Del_UpdateListViewContentAsyn del = new Del_UpdateListViewContentAsyn(Invoke_UpdateListViewContentAsynUI);
        //    ,           
        IAsyncResult iresult = del.BeginInvoke(10,12.1, null, null);
        while (!iresult.IsCompleted)
            Application.DoEvents();//        UI  ,     UI    !
        //      
        int result = del.EndInvoke(iresult);
        //UI    
        //UI_lv_content.Items.Clear();
        UI_lv_content.Items.Add("finished : " + result);
        UI_lv_content.Update();
    }
    //              (  C)
    private delegate int Del_UpdateListViewContentAsyn(int max,double min);
    //          -   UI
    private int Invoke_UpdateListViewContentAsyn(int max,double min)
    {
        Thread.Sleep(2000);
        return new Random().Next(20);
    }
    

    为了在子线程运行过程中,不造成主线程拥塞,一定要对主线程拥塞进行处理

    实例代码2:需要修改UI的子线程处理

    //          -   UI
    private int Invoke_UpdateListViewContentAsynUI(int max, double value)
    {
        //                UI   -    
        for (int i = 0; i < 5; i++)
        {
            if (UI_lv_content.InvokeRequired)//                 (         Thread  ,    2)
                UI_lv_content.Invoke(new Del_UpdateListViewContentParam(Invoke_UpdateListViewContent), i);
            else
            Invoke_UpdateListViewContent();
        }
        Thread.Sleep(2000);
        return new Random().Next(20); 
    }

    기타 고려 사항
    주 스레드 혼잡 처리
    Thread 객체의 주 정체 처리
    Thread thread = new Thread(start);
    thread.Start();
    while (thread.IsAlive)        
        Application.DoEvents();

    함수 의뢰의 혼잡 처리
    IAsyncResult iresult = del.BeginInvoke(10,12.1, null, null);
    while (!iresult.IsCompleted)
        Application.DoEvents();

    간단한 백엔드 처리 모듈 BackgroundWorker
    설명
  • 현식 스레드 생성 과정 없음
  • UI 수정 위임 프로세스가 명시적으로 표시되지 않음
  • 백그라운드 처리와 처리가 완료된 조작을 명확하게 감청할 수 있다
  • 기본 스레드 혼잡 유지 관리 없음
  • 이 객체는 Android 플랫폼의 AsynTask 클래스와 매우 유사합니다.
    인스턴스 코드
  • 인터페이스에서 비 UI 컨트롤을 드래그하려면: BackgroundWorker
  • 또는 직접 코드로 만들지만 BackgroundWorker에 수동으로 감청 이벤트를 등록해야 합니다
  • this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
    this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
    this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);

    구체적인 사용 코드
    private void UI_btn_start5_Click(object sender, EventArgs e)
    {
        //  backgroundWorker1       
        backgroundWorker1.WorkerReportsProgress = true;
        backgroundWorker1.RunWorkerAsync();
        //UI  
        UI_lv_content.Items.Clear();
    }
    
    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        //      
        for (int i = 1; i < 11; i++)
        {
            Thread.Sleep(1000);
            //    UI  
            backgroundWorker1.ReportProgress(i,""+i);
        }
        //    
        e.Result = new Random().Next(25);
    
    }
    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        //          ,       ,       UI 
        UI_lv_content.Items.Add(String.Format("doing... {0}/10, value : {1}",e.ProgressPercentage,e.UserState.ToString()));
        UI_lv_content.Update();
    }
    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        //          
        UI_lv_content.Items.Add("finish:"+e.Result);
    }

    좋은 웹페이지 즐겨찾기