📁 [4] 개발자 정보 & 코드 노트/C#
C# Windows Forms 강의 93편: 멀티스레드를 활용한 백그라운드 작업 처리
wawManager
2025. 5. 7. 12:00
1. 강의 개요
이번 강의에서는 멀티스레드를 활용하여 Windows Forms 애플리케이션에서
백그라운드 작업을 처리하는 방법을 학습합니다.
Windows Forms 애플리케이션은 기본적으로 단일 스레드에서 실행되기 때문에,
시간이 오래 걸리는 작업을 수행하면 UI가 멈출 수 있습니다.
이 문제를 해결하기 위해 BackgroundWorker와 Task를 사용하여
비동기 작업을 구현합니다.
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 #비동기작업