반응형
1. SynchronizationContext란?
SynchronizationContext는 코드 실행 컨텍스트를 추상화한 클래스입니다. 주로 스레드 간 작업을 조율할 때 사용되며, 특히 UI 스레드와 작업 스레드 간의 통신에서 매우 유용합니다.
public class SynchronizationContext
{
public virtual void Post(SendOrPostCallback d, object state);
public virtual void Send(SendOrPostCallback d, object state);
}
2. 왜 사용해야 하는가?
2.1 기존 Dispatcher.Invoke 방식의 문제점
// UI 스레드에서 실행되어야 하는 코드
Application.Current.Dispatcher.Invoke(() =>
{
LastLog = "처리 완료";
Progress = 100;
});
- 명시적인 Dispatcher 호출이 필요
- WPF에 종속적인 코드
- 블로킹 방식으로 동작하여 성능 저하 가능
- 코드가 지저분해짐
2.2 SynchronizationContext의 장점
private readonly SynchronizationContext _uiContext;
public DeepLearningBase()
{
_uiContext = SynchronizationContext.Current; // UI 스레드의 컨텍스트 캡처
}
protected void UpdateUI()
{
_uiContext?.Post(_ =>
{
LastLog = "처리 완료";
Progress = 100;
}, null);
}
- 플랫폼 독립적 (WPF, WinForms, ASP.NET 등)
- 비동기적 실행으로 성능 향상
- 더 깔끔한 코드
- 테스트 용이성 향상
3. 기본 사용법
3.1 UI 컨텍스트 캡처
public class MyViewModel
{
private readonly SynchronizationContext _uiContext;
public MyViewModel()
{
// 반드시 UI 스레드에서 생성자 호출
_uiContext = SynchronizationContext.Current;
}
}
3.2 Post vs Send
// 비동기 실행 (권장)
_uiContext.Post(_ => UpdateUI(), null);
// 동기 실행 (블로킹)
_uiContext.Send(_ => UpdateUI(), null);
3.3 이벤트 처리 예제
private void ProcessEvents()
{
foreach (var args in _eventQueue.GetConsumingEnumerable())
{
_uiContext?.Post(_ =>
{
switch (args)
{
case StatusUpdateEventArgs status:
StatusUpdated?.Invoke(this, status);
break;
case ProgressUpdateEventArgs progress:
ProgressUpdated?.Invoke(this, progress);
break;
}
}, null);
}
}
4. 사용하면 좋은 상황
4.1 장시간 실행되는 작업
public async Task LongRunningOperation()
{
await Task.Run(() =>
{
// 무거운 작업 수행
for (int i = 0; i < 100; i++)
{
// 진행 상황 UI 업데이트
_uiContext?.Post(_ =>
{
Progress = i;
LastLog = $"처리중... {i}%";
}, null);
}
});
}
4.2 이벤트 기반 시스템
public class EventProcessor
{
private readonly SynchronizationContext _uiContext;
public void OnDataReceived(object sender, DataEventArgs e)
{
// 데이터 처리는 백그라운드에서
Task.Run(() =>
{
var result = ProcessData(e.Data);
// UI 업데이트는 UI 스레드에서
_uiContext?.Post(_ =>
{
UpdateUIWithResult(result);
}, null);
});
}
}
5. 주의 사항
1. 컨텍스트 캡처 시점
- 반드시 UI 스레드에서 SynchronizationCentext.Current를 캡처해야함
- 작업 스레드에서 캡처하면 null이 될 수 있음
2. 메모리 누수 방지
public void Dispose()
{
_uiContext = null; // 참조 해제
}
3. 성능 고려
Post는 비동기적으로 동작하므로 Send보다 선호
너무 잦은 UI 업데이트는 피해야함
결론
SynchronizationContext는 UI 스레드와 작업 스레드 간의 통신을 추상화하고 단순화합니다. 특히 이벤트 기반 시스템이나 장시간 실행되는 작업에서 UI 업데이트를 처리할 때 매우 유용합니다. Dispatcher.Invoke보다 더 유연하고 플랫폼 독립적인 방식을 제공하며, 코드의 가독성과 유지보수성을 향상시킵니다.
반응형
'프로그래밍 > WPF' 카테고리의 다른 글
[WPF] 이벤트: PreviewMouseDown과 MouseDown의 차이 (0) | 2024.11.18 |
---|---|
[WPF] DataGrid 가상화와 ComboBox SelectedItem 불일치 문제 해결: MVVM 패턴에서의 효율적인 접근 방법 (0) | 2024.10.15 |
[WPF] DataGrid 행 더블 클릭 시 Command 실행하기 (0) | 2023.11.03 |
[WPF] HelixToolkit.Wpf.SharpDX 사용하여 3D 공간에서 마우스 드래그로 선택 영역 그리기 (0) | 2023.10.30 |
[WPF] Slider 드래그 완료 시점에 값 업데이트하기 (0) | 2023.07.26 |