728x90
멀티스레드 프로그래밍에서 Mutex, Semaphore, 그리고 Critical Section은 동기화 메커니즘의 대표적인 예입니다. 이 글에서는 각 메커니즘의 성능 차이를 C++ 프로그램을 통해 비교하고, 동시에 프로그램의 진행 상태를 확인할 수 있도록 진행 바(progress bar)를 추가하는 방법을 설명합니다.
1. C++ 코드: Mutex, Semaphore, Critical Section 비교
아래 코드는 Mutex, Semaphore, Critical Section을 각각 사용하여 공유 자원에 접근하고, 성능을 비교하는 예제입니다. 또한 프로그램의 진행 상태를 실시간으로 관찰할 수 있도록 1%마다 진행 바를 출력하도록 하였습니다.
// C++ 코드
#include <iostream>
#include <thread>
#include <mutex>
#include <semaphore.h>
#include <atomic>
#include <chrono>
#include <iomanip> // for std::setw
const int NUM_THREADS = 4;
const int NUM_ITERATIONS = 1000000;
int counter = 0; // 공유 자원
// Mutex
std::mutex mtx;
// Semaphore (POSIX semaphore)
sem_t sem;
// Critical Section (using atomic operation for comparison)
std::atomic<int> atomic_counter(0);
// Progress bar function
void print_progress(int current, int total) {
int bar_width = 70;
float progress = (float)current / total;
std::cout << "[";
int pos = bar_width * progress;
for (int i = 0; i < bar_width; ++i) {
if (i < pos)
std::cout << "=";
else if (i == pos)
std::cout << ">";
else
std::cout << " ";
}
std::cout << "] " << int(progress * 100.0) << " %\r";
std::cout.flush();
}
// Shared resource access function for Mutex
void increment_with_mutex() {
for (int i = 0; i < NUM_ITERATIONS; ++i) {
mtx.lock();
++counter;
mtx.unlock();
if (i % (NUM_ITERATIONS / 100) == 0) {
print_progress(i, NUM_ITERATIONS); // Print progress every 1%
}
}
}
// Shared resource access function for Semaphore
void increment_with_semaphore() {
for (int i = 0; i < NUM_ITERATIONS; ++i) {
sem_wait(&sem);
++counter;
sem_post(&sem);
if (i % (NUM_ITERATIONS / 100) == 0) {
print_progress(i, NUM_ITERATIONS); // Print progress every 1%
}
}
}
// Shared resource access function for atomic (Critical Section)
void increment_with_atomic() {
for (int i = 0; i < NUM_ITERATIONS; ++i) {
++atomic_counter;
if (i % (NUM_ITERATIONS / 100) == 0) {
print_progress(i, NUM_ITERATIONS); // Print progress every 1%
}
}
}
int main() {
// Semaphore initialization
sem_init(&sem, 0, 1);
// Measure execution time for Mutex
counter = 0;
auto start_time = std::chrono::high_resolution_clock::now();
std::thread threads_mutex[NUM_THREADS];
std::cout << "Running Mutex Test..." << std::endl;
for (int i = 0; i < NUM_THREADS; ++i) {
threads_mutex[i] = std::thread(increment_with_mutex);
}
for (int i = 0; i < NUM_THREADS; ++i) {
threads_mutex[i].join();
}
auto end_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> mutex_time = end_time - start_time;
std::cout << "\nMutex time: " << mutex_time.count() << " seconds, counter: " << counter << std::endl;
// Measure execution time for Semaphore
counter = 0;
start_time = std::chrono::high_resolution_clock::now();
std::thread threads_semaphore[NUM_THREADS];
std::cout << "Running Semaphore Test..." << std::endl;
for (int i = 0; i < NUM_THREADS; ++i) {
threads_semaphore[i] = std::thread(increment_with_semaphore);
}
for (int i = 0; i < NUM_THREADS; ++i) {
threads_semaphore[i].join();
}
end_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> semaphore_time = end_time - start_time;
std::cout << "\nSemaphore time: " << semaphore_time.count() << " seconds, counter: " << counter << std::endl;
// Measure execution time for Critical Section (atomic)
atomic_counter = 0;
start_time = std::chrono::high_resolution_clock::now();
std::thread threads_atomic[NUM_THREADS];
std::cout << "Running Atomic Test..." << std::endl;
for (int i = 0; i < NUM_THREADS; ++i) {
threads_atomic[i] = std::thread(increment_with_atomic);
}
for (int i = 0; i < NUM_THREADS; ++i) {
threads_atomic[i].join();
}
end_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> atomic_time = end_time - start_time;
std::cout << "\nAtomic time: " << atomic_time.count() << " seconds, counter: " << atomic_counter.load() << std::endl;
// Cleanup
sem_destroy(&sem);
return 0;
}
2. 컴파일 및 실행 방법
아래 명령어로 코드를 컴파일하고 실행할 수 있습니다:
g++ -std=c++11 -pthread -o sync_test_with_progress sync_test_with_progress.cpp
./sync_test_with_progress
프로그램이 실행되는 동안 0%부터 100%까지의 진행 상태를 실시간으로 관찰할 수 있습니다.
3. 결론
이 포스팅에서는 Mutex, Semaphore, Critical Section을 사용하여 공유 자원을 보호하는 방법과 이들의 성능 차이를 비교하는 방법을 설명하였습니다. 각 동기화 메커니즘은 서로 다른 성능 특성을 가지며, 이를 사용함에 있어 상황에 맞는 선택이 필요합니다. 진행 상태를 출력하는 기능을 추가함으로써 프로그램의 동작을 실시간으로 확인하는 방법도 소개하였습니다.
728x90
'MFC(Window Programming)' 카테고리의 다른 글
| [linux]ffmpeg mp4 player (0) | 2024.10.23 |
|---|---|
| [linux]C++에서 fork와 exec를 사용해 명령 실행하기 (0) | 2024.10.11 |
| ifstream, ostream, stringstream, std::getline (1) | 2024.09.25 |
| C++ 정규식과 Raw String Literal: 매칭과 사용법 (1) | 2024.09.24 |
| OnSize 함수 호출 방법 MFC (0) | 2021.01.07 |