본문 바로가기
📁 [4] 개발자 정보 & 코드 노트/C#

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

by wawManager 2025. 5. 7.

 

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 #비동기작업