2020년 7월 26일 일요일

WPF - Thread, CompositionTarget

백그라운드 작업

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void btnRun02_Click(object sender, RoutedEventArgs e)
{
    worker = new BackgroundWorker();
    worker.WorkerSupportsCancellation = true;
    worker.WorkerReportsProgress = true;
    worker.ProgressChanged += Worker_ProgressChanged;
    worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
    worker.DoWork += Worker_DoWork;
    worker.RunWorkerAsync(10000);
}

...

worker.CancelAsync();
cs

위 작업들이 기본작업임.

DoWork 는 subthread 이고 나머지 두개인 ProgressChanged, RunWorkerCompleted 는 mainthread 에서 작업되어 컨트롤을 직접 건들일 수 있음.

CancelAsync() 로 중간에 중단할 수 있음.

RunWorkerAnsync 의 인자는 DoWorker 의 e 로 이동함.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
    int sum = 0;
    var intMax = (int)e.Argument;
 
    for (int i = 0; i < intMax; i++)
    {
        var percent = (int)((double)i / intMax * 100);
        if (i % 3 == 0 && i % 4 == 0)
        {
            if(((BackgroundWorker)sender).CancellationPending)
            {
                e.Cancel = true;
                return;
            }
            System.Threading.Thread.Sleep(1);
            ((BackgroundWorker)sender).ReportProgress(percent, "===>" + i);
        }
        sum += 1;
 
        ((BackgroundWorker)sender).ReportProgress(percent);
    }
    e.Result = sum;
}
cs

DoWork 에서 sender 는 위에서 생성한 BackgroundWorker 객체임.

여기서 ReportProgress 를 호출하면서 두 인자를 ProgressChanged 함수로 보낼 수 있음.
e.Result 에 값을 넣으면 RunWorkerCompleted 의 인자로 값을 보낼 수 있음.

외부에서 Cancel 되었을 때를 고려해서 주기적으로 CancellationPending 을 검사해야서 중간에 처리해줘야함.
이때 e.Cancel 에 True 를 해서 뒤에서 쓰는 것이 관행임.


1
2
3
4
5
6
7
8
private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    pgb01.Value = e.ProgressPercentage;

    if(e.UserState != null)
        lst01.Items.Add(e.UserState);
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if(e.Cancelled)
    {
        MessageBox.Show("처리중지");
        return;
    }
    else
    {
        MessageBox.Show(e.Result.ToString());
    }
}
cs

각각 보낸 인자를 저렇게 꺼낼 수 있음.

RunWorkerCompleted 에서 e.Cancelled 를 사용해 처리하지 않으면 에러발생할 가능성이 큼.


Composition Target

display target 을 말하며, Rendering 이벤트에 함수를 추가하면 프로그램이 렌더링 될 때마다 함수가 메인 스레드에서 호출이 된다.






댓글 없음:

댓글 쓰기

List