📁 [4] 개발자 정보 & 코드 노트/C#

C# Windows Forms 강의 93편: 멀티스레드를 활용한 백그라운드 작업 처리

wawManager 2025. 5. 7. 12:00

 

1. 강의 개요

이번 강의에서는 멀티스레드를 활용하여 Windows Forms 애플리케이션에서
백그라운드 작업을 처리하는 방법을 학습합니다.
Windows Forms 애플리케이션은 기본적으로 단일 스레드에서 실행되기 때문에,
시간이 오래 걸리는 작업을 수행하면 UI가 멈출 수 있습니다.
이 문제를 해결하기 위해 BackgroundWorkerTask를 사용하여
비동기 작업을 구현합니다.


2. 학습 목표

  • BackgroundWorker를 사용한 비동기 작업 처리
  • UI와 작업 스레드 간 안전한 데이터 교환
  • ProgressBar를 활용한 작업 진행 상태 표시
  • Task를 사용한 비동기 프로그래밍 구현

3. 기능 요구사항

필수 기능

1️⃣ 시간이 오래 걸리는 작업 처리:

  • 긴 작업을 백그라운드 스레드에서 실행

2️⃣ 작업 진행 상태 표시:

  • ProgressBar를 사용해 진행 상황 시각화

3️⃣ 작업 중 UI 응답 유지:

  • 비동기 작업 중에도 UI가 멈추지 않도록 구현

4. 실습: 멀티스레드 백그라운드 작업 애플리케이션 제작

1️⃣ 폼 구성

  • 폼(Form) 이름: Form1
  • 컨트롤 배치:

컨트롤 타입 이름 위치 크기

Button btnStart 폼 상단 왼쪽 (100 x 30)
ProgressBar progressBar 폼 상단 오른쪽 (300 x 30)
Label lblStatus 폼 하단 전체 (400 x 30)

📌 폼 디자인 예시:

--------------------------------------------------
| [Start 버튼]                     [ProgressBar] |
--------------------------------------------------
| [Status Label - 진행 상태 표시]               |
--------------------------------------------------

2️⃣ 코드 작성

(1) BackgroundWorker를 사용한 비동기 작업

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApp_BackgroundWorker
{
    public partial class Form1 : Form
    {
        private BackgroundWorker _backgroundWorker;

        public Form1()
        {
            InitializeComponent();
            InitializeBackgroundWorker();
        }

        // BackgroundWorker 초기화
        private void InitializeBackgroundWorker()
        {
            _backgroundWorker = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };

            _backgroundWorker.DoWork += BackgroundWorker_DoWork;
            _backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
            _backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
        }

        // 작업 시작
        private void btnStart_Click(object sender, EventArgs e)
        {
            if (!_backgroundWorker.IsBusy)
            {
                lblStatus.Text = "작업 시작...";
                progressBar.Value = 0;
                _backgroundWorker.RunWorkerAsync();
            }
        }

        // 백그라운드 작업 수행
        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 0; i <= 100; i++)
            {
                if (_backgroundWorker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                Thread.Sleep(50); // 작업 시뮬레이션
                _backgroundWorker.ReportProgress(i);
            }
        }

        // 진행 상태 업데이트
        private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar.Value = e.ProgressPercentage;
            lblStatus.Text = $"진행률: {e.ProgressPercentage}%";
        }

        // 작업 완료 시 실행
        private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                lblStatus.Text = "작업이 취소되었습니다.";
            }
            else if (e.Error != null)
            {
                lblStatus.Text = $"오류 발생: {e.Error.Message}";
            }
            else
            {
                lblStatus.Text = "작업이 완료되었습니다.";
            }
        }
    }
}

(2) Task를 사용한 비동기 작업

        // Task를 사용한 비동기 작업
        private async void btnStartTask_Click(object sender, EventArgs e)
        {
            lblStatus.Text = "작업 시작...";
            progressBar.Value = 0;

            try
            {
                await Task.Run(() =>
                {
                    for (int i = 0; i <= 100; i++)
                    {
                        Invoke(new Action(() =>
                        {
                            progressBar.Value = i;
                            lblStatus.Text = $"진행률: {i}%";
                        }));

                        Thread.Sleep(50); // 작업 시뮬레이션
                    }
                });

                lblStatus.Text = "작업이 완료되었습니다.";
            }
            catch (Exception ex)
            {
                lblStatus.Text = $"오류 발생: {ex.Message}";
            }
        }

(3) Designer 코드

        private void InitializeComponent()
        {
            this.btnStart = new Button();
            this.progressBar = new ProgressBar();
            this.lblStatus = new Label();

            // Start Button 설정
            this.btnStart.Location = new System.Drawing.Point(10, 10);
            this.btnStart.Size = new System.Drawing.Size(100, 30);
            this.btnStart.Text = "Start";
            this.btnStart.Click += new EventHandler(this.btnStart_Click);

            // ProgressBar 설정
            this.progressBar.Location = new System.Drawing.Point(120, 10);
            this.progressBar.Size = new System.Drawing.Size(300, 30);

            // Status Label 설정
            this.lblStatus.Location = new System.Drawing.Point(10, 50);
            this.lblStatus.Size = new System.Drawing.Size(400, 30);
            this.lblStatus.Text = "상태: 준비 완료";

            // Form 설정
            this.ClientSize = new System.Drawing.Size(450, 100);
            this.Controls.Add(this.btnStart);
            this.Controls.Add(this.progressBar);
            this.Controls.Add(this.lblStatus);
            this.Text = "백그라운드 작업 처리";
        }

3️⃣ 실행 결과

1️⃣ BackgroundWorker 사용

  • "Start" 버튼 클릭 → ProgressBar와 Label에 진행률 표시

2️⃣ Task 사용

  • UI가 멈추지 않고 비동기 작업 처리 및 진행률 표시

5. 주요 개념 요약

  • BackgroundWorker: Windows Forms에서 백그라운드 작업을 처리하는 기본 클래스
  • ProgressChanged 이벤트: 작업 진행 상태 업데이트
  • RunWorkerCompleted 이벤트: 작업 완료 또는 취소 시 처리
  • Task: 비동기 작업 처리를 위한 더 현대적인 방법

 

📌 #CSharp #WindowsForms #멀티스레드 #BackgroundWorker #Task #비동기작업