경쟁 상태, 뮤텍스, 세마포어는 멀티스레딩 및 병렬 프로그래밍과 관련된 개념으로, DirectX 11에도 적용될 수 있다. 레이스 조건, 뮤텍스, 세마포어는 멀티 스레드 프로그래밍에서 중요한 개념이며, 공유 리소스와 병렬 실행을 다룰 때 DirectX 11 프로그래밍에도 적용될 수 있다. 개발자는 뮤트크세스 및 세마포어와 같은 동기화 원시 요소를 사용하여 공유 리소스에 대한 안전하고 효율적인 액세스를 보장하고 경쟁 조건을 피할 수 있다.

 

목차

     

     


     

     

    Mutex

     

    경쟁 상태, 뮤텍스, 세마포어는 멀티스레딩 및 병렬 프로그래밍과 관련된 개념으로, DirectX 11에도 적용될 수 있다. 

    경쟁 상태, 뮤텍스, 세마포어는 멀티 스레드 프로그래밍에서 중요한 개념이며, 공유 리소스와 병렬 실행을 다룰 때 DirectX 11 프로그래밍에도 적용될 수 있다. 개발자는 뮤트크세스 및 세마포어와 같은 동기화 원시 요소를 사용하여 공유 리소스에 대한 안전하고 효율적인 액세스를 보장하고 경쟁 상태를 피할 수 있다.

     

     


    경쟁 상태 (Race Condition) 

     

    경쟁 상태(Race Condition)는 둘 이상의 스레드(Thread)가 공유 리소스(예: 변수, 파일, 메모리 위치)에 동시에 액세스할 때 발생하며, 최종 결과는 스레드 실행 순서와 타이밍에 따라 달라진다. 이로 인해 예기치 않은 동작, 데이터 손상 또는 프로그램 충돌이 발생할 수 있다. DirectX 11에서 여러 스레드가 동일한 리소스(예: 버퍼, 텍스처, 셰이더)를 동시에 수정하려고 할 때 경쟁 상태(Race Condition)가 발생할 수 있으며, 이로 인해 시각적 아티팩트, 깜박임 또는 잘못된 렌더링이 발생할 수 있다.

     

    https://zangzangs.tistory.com/115


     

    뮤텍스(Mutex)와 세마포어(Semaphore)

     

    뮤텍스(Mutex)는 한 번에 하나의 스레드(Thread)만 공유 리소스에 액세스할 수 있는 동기화 기본 요소이다. 스레드(Thread)가 뮤텍스(Mutex)를 획득하면 리소스에 대한 독점적인 액세스 권한을 얻는 반면, 뮤텍스를 획득하려는 다른 스레드는 뮤텍스가 해제될 때까지 차단된다. 이렇게 하면 경쟁 상태(Race Condition)을 방지하고 일관되고 안전한 방식으로 리소스에 액세스할 수 있습니다. DirectX 11에서 뮤트크세스는 명령 목록, 렌더 대상 또는 스왑 체인과 같은 공유 리소스에 대한 액세스를 동기화하는 데 사용할 수 있습니다.

    세마포어(Semaphore)는 여러 스레드(Multi-threads)가 공유 리소스에 액세스할 수 있지만 용량이나 가용성이 제한된 또 다른 동기화 기본 요소이다. 세마포어는 리소스에 동시에 액세스할 수 있는 스레드 수를 지정하는 카운터를 유지한다. 스레드가 리소스에 액세스하려면 먼저 스레드를 위한 공간을 예약하는 세마포어 카운터(양의 경우)를 줄여야 합니다. 스레드(Thread)가 완료되면 다른 스레드가 리소스에 액세스할 수 있도록 세마포어 카운터(스폿을 해제함)를 늘려야 합니다. DirectX 11에서 세마포어는 GPU 명령 큐, 펜스 또는 동기화 개체와 같은 제한된 수의 슬롯 또는 대기열을 가진 리소스에 대한 액세스를 관리하는 데 사용될 수 있다.

     

    더보기

    Race condition, mutex, and semaphore are concepts related to multi-threading and parallel programming, which can also apply to DirectX 11.

    Race condition occurs when two or more threads access a shared resource (e.g. a variable, a file, a memory location) simultaneously, and the final result depends on the order and timing of the thread execution. This can lead to unexpected behavior, data corruption, or program crashes. In DirectX 11, race conditions can occur when multiple threads try to modify the same resources (e.g. buffers, textures, shaders) simultaneously, which can cause visual artifacts, flickering, or incorrect rendering.

    Mutex (short for mutual exclusion) is a synchronization primitive that allows only one thread to access a shared resource at a time. When a thread acquires a mutex, it gains exclusive access to the resource, while other threads that try to acquire the mutex will be blocked until the mutex is released. This prevents race conditions and ensures that the resource is accessed in a consistent and safe manner. In DirectX 11, mutexes can be used to synchronize access to shared resources such as command lists, render targets, or swap chains.

    Semaphore is another synchronization primitive that allows multiple threads to access a shared resource, but with a limited capacity or availability. A semaphore maintains a counter that specifies the number of threads that can access the resource simultaneously. When a thread wants to access the resource, it must first decrement the semaphore counter (if it is positive), which reserves a spot for the thread. When the thread is done, it must increment the semaphore counter (which releases the spot), allowing other threads to access the resource. In DirectX 11, semaphores can be used to manage access to resources with a limited number of slots or queues, such as GPU command queues, fences, or synchronization objects.

    In summary, race condition, mutex, and semaphore are important concepts in multi-threaded programming, and can also apply to DirectX 11 programming when dealing with shared resources and parallel execution. By using synchronization primitives such as mutexes and semaphores, developers can ensure safe and efficient access to shared resources and avoid race conditions.

     

    https://worthpreading.tistory.com/90

     

    https://iredays.tistory.com/125

     

    [운영체제] Race Condition과 예방할 방법(세마포어, 뮤텍스)

    1. Race Condition에 대해 race condition이란 두 개 이상의 프로세스가 공통 자원을 병행적으로(concurrently) 읽거나 쓰는 동작을 할 때, 공용 데이터에 대한 접근이 어떤 순서에 따라 이루어졌는지에 따라

    iredays.tistory.com


     

    ThreadDemo

     

    ThreadDemo.h

    더보기
    #pragma once
    #include "Systems/IExecute.h"
    
    class ThreadDemo : public IExecute
    {
    public:
    	virtual void Initialize() override;
    	virtual void Ready() override {}
    	virtual void Destroy() override {}
    	virtual void Update() override;
    	virtual void PreRender() override {}
    	virtual void Render() override;
    	virtual void PostRender() override {}
    	virtual void ResizeScreen() override {}
    
    private:
    	void Loop();
    
    	void Function();
    	
    	void MultiThread();
    	void MultiThread1();
    	void MultiThread2();
    
    	void Join();
    
    	void Mutex();
    	void MutexUpdate();
    
    	void RaceCondition(int& counter);
    	void Execute();
    
    private:
    	mutex m;
    	float progress = 0.0f;
    };

     

     

    ThreadDemo.cpp

    더보기
    #include "stdafx.h"
    #include "ThreadDemo.h"
    
    void ThreadDemo::Initialize()
    {
    	//Loop();
    
    	//function<void()> f = bind(&ThreadDemo::Function, this);
    	//f();
    
    	//MultiThread();
    
    	//Join();
    
    	//Mutex();
    	
    	Execute();
    }
    
    void ThreadDemo::Update()
    {
    	//MutexUpdate();
    
    }
    
    void ThreadDemo::Render()
    {
    	
    }
    
    void ThreadDemo::Loop()
    {
    	for (int i = 0; i < 100; i++)
    		printf("1 : %d\n", i);
    	printf("반복문1 종료\n");
    
    	for (int i = 0; i < 100; i++)
    		printf("2 : %d\n", i);
    	printf("반복문2 종료\n");
    }
    
    void ThreadDemo::Function()
    {
    	printf("함수 포인터 호출\n");
    }
    
    void ThreadDemo::MultiThread()
    {
    	thread t(bind(&ThreadDemo::MultiThread1, this));
    	thread t2(bind(&ThreadDemo::MultiThread2, this));
    
    	t2.join();
    	printf("t2.join\n");
    
    	t.join();
    	printf("t.join\n");
    }
    
    void ThreadDemo::MultiThread1()
    {
    	for (int i = 0; i < 100; i++)
    		printf("1 : %d\n", i);
    	printf("반복문1 종료\n");
    }
    
    void ThreadDemo::MultiThread2()
    {
    	for (int i = 0; i < 100; i++)
    		printf("2 : %d\n", i);
    	printf("반복문2 종료\n");
    }
    
    void ThreadDemo::Join()
    {
    	thread t([]()
    	{
    		for (int i = 0; i < 100; i++)
    			printf("1 : %d\n", i);
    		printf("반복문1 종료\n");
    	});
    
    	thread t2([]()
    	{
    		int a = 0;
    		while (true)
    		{
    			a++;
    			printf("A : %d\n", a);
    
    			Sleep(100);
    
    			if (a > 30)
    				break;
    		}
    	});
    
    	printf("멀티 쓰레드 시작\n");
    
    	t2.join();
    	printf("t2 join\n");
    
    	t.join();
    	printf("t.join\n");
    }
    
    void ThreadDemo::Mutex()
    {
    	thread t([&]()
    	{
    		while (true)
    		{
    			Sleep(1000);
    
    			printf("Progress : %f\n", progress);
    		}
    	});
    	t.detach(); //detach는 종료가 되는 말든 다음으로 넘어간다. 
    }
    
    void ThreadDemo::MutexUpdate()
    {
    	progress += 0.01f;
    
    	ImGui::ProgressBar(progress / 1000.0f);
    }
    
    void ThreadDemo::RaceCondition(int & counter)
    {
    	for (int i = 0; i < 10000000; i++)
    	{
    		//counter++; //counter++을 m.lock()을 안해주면 cpu연산 중에 뺏어간다.
    		m.lock();
    		{
    			counter++; 
    		}
    		m.unlock();
    	}
    		
    }
    
    void ThreadDemo::Execute()
    {
    	int counter = 0;
    
    	vector<thread> threads;
    	for (int i = 0; i < 4; i++)
    	{
    		function<void(int&)> f = bind(&ThreadDemo::RaceCondition, this, placeholders::_1);
    
    		threads.push_back(thread(f, ref(counter)));
    	}
    
    	for (int i = 0; i < 4; i++)
    		threads[i].join(); //종료
    
    	printf("Counter : %d\n", counter);
    }

     

    Thread는 작업을 순차적으로 하지 않는 경우가 발생하 수 있다. 따라서 뮤택스 설계에 유의해야 한다.

    추후에 배울 Direct Compute Shader는 Thread를 작동한다. 

     

    join는 종료될 때까지 대기.

    detach는 종료가 되든말든 다음으로 넘어간다. 나중에 자신의 Thread가 모두 종료되면 join을 시켜준다.

     

     


     

    실행화면

     

     

    '⭐ DirectX > DirectX11 3D' 카테고리의 다른 글

    [DirectX11] 059 Raw Buffer  (0) 2023.02.28
    [DirectX11] 058 Direct Compute  (0) 2023.02.27
    [DirectX11] 056 Thread  (0) 2023.02.22
    [DirectX11] 055 Framework  (0) 2023.02.22
    [DirectX11] 053~54 Instancing Animation, Process vs. Thread  (0) 2023.02.21