C++ Multithreaded Programming

김현수·2025년 5월 20일
0
  • C++11
    • 처음으로 threads, mutexes(locks), conditional variables 사용
  • C++17
    • Parrallel STL

C++ Thread Library

  • <thread> header file 사용
  • std::thread를 통해 사용 가능
    • thread(func(실행할 함수), args...)
    • func이 return을 만날 때, thread는 종료됨
  • thread를 생성하는 4가지 방법
    • function pointer 사용
    • functor (function object) 사용
    • class member function 사용
    • lambda expression 사용
  • join()
    • thread가 끝날 때까지 기다림
  • detach()
    • 독립적으로 thread가 수행함
    • detach() 이후, join이 허용되지 않음
    • thread가 detach()없이 없애면 error가 생김
  • mutex
    • <mutex> header file 사용
    • std::lock_guard는 mutex가 생성할 때 lock을 걸고 destruction할 때 unlock을 함.
#include <mutex>
std::mutex m;
m.lock();
m.unlock();
  • atomic
    • 연산을 atomic하게 함
    • mutex lock보다 빠름
std::atomic<int> ai(o)
ai = 10; //10
std::cout << ai;
++ai; //11
--ai; //10

code

thread 생성

#include <iostream>
#include <thread>
#include <stdio.h>

long OddSum=0;
long EvenSum=0;

void findEven(long start, long end)
{
    for (long i=start;i<=end;i++) if ((i&1)==0) EvenSum += i;
}

void findOdd(long start, long end)
{
    for (long i=start;i<=end;i++) if ((i&1)==1) OddSum += i;
}


// Functor (Function Object)
class FindOddFunctor {
    public:
        void operator()(int start, int end) {
            for (int i=start;i<=end;i++) if ((i&1)==1) OddSum += i;
        }
};

// class member function
class FindOddClass {
	public:
		void myrun(int start, int end) {
            for (int i=start;i<=end;i++) if ((i&1)==1) OddSum += i;
		}
};


int main()
{
    long start = 0, end = 1000;

    std::thread t1(findEven, start, end);

    //std::thread t2(findOdd, start, end);   // (method 1) create thread using function pointer

	//FindOddFunctor findoddfunctor;
    //std::thread t2(findoddfunctor, start, end); // (method 2) create thread using functor

	//FindOddClass oddObj;
    //std::thread t2(&FindOddClass::myrun, &oddObj, start, end); // (method 3) create thread using member function of an object

	// (method 4) create thread using lambda function
	std::thread t2([&](long s, long e) {
		for (long i=s;i<=e;i++) if ((i&1)==1) OddSum += i;
	}, start, end);
		
    t1.join(); // wait until thread t1 is finished.
    t2.join(); // wait until thread t2 is finished.
    //t2.detach(); // continue to run without waiting

    std::cout << "OddSum: " << OddSum << std::endl;
    std::cout << "EvenSum: " << EvenSum << std::endl;

    return 0;
}

count no lock

#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>

int inc_num=10001234;
int dec_num=10000000;

class CountLock {
	int count;
public:
	CountLock() : count(0) {}
	int getCount() 
	{
		return count;
	}
	
	void inc()
	{
		count++;
	}

	void dec()
	{
		count--;
	}
};
 
class Producer
{
	CountLock& c_lock;
public:
	Producer(CountLock& clock): c_lock(clock) {
	}

	void run() {
		for (int i=0;i<inc_num;i++) c_lock.inc();
	}
};

class Consumer
{
	CountLock& c_lock;
public:
	Consumer(CountLock& clock): c_lock(clock) {
	}

	void run() {
		for (int i=0;i<dec_num;i++) c_lock.dec();
	}
};
 
int main()  
{
    CountLock count_lock;
    Producer p(count_lock);
    Consumer c(count_lock);
    std::thread threadP(&Producer::run,&p);
    std::thread threadC(&Consumer::run,&c);
    threadP.join();    
    threadC.join();    
    std::cout<<"after main join count:"<<count_lock.getCount()<<std::endl;
    return 0;
}

counter lock

#include <iostream>
#include <thread>
#include <mutex>

int inc_num=10001234;
int dec_num=10000000;

std::mutex m;

class CountLock {
	int count;
public:
	CountLock() : count(0) {}
	int getCount() 
	{
		int val;
		m.lock();
		val = count;
		m.unlock();
		return val;
	}
	
	void inc()
	{
		m.lock();
		count++;
		m.unlock();
	}

	void dec()
	{
		m.lock();
		count--;
		m.unlock();
	}
};
 
class Producer
{
	CountLock& c_lock;
public:
	Producer(CountLock& clock): c_lock(clock) {
	}

	void run() {
		for (int i=0;i<inc_num;i++) c_lock.inc();
	}
};

class Consumer
{
	CountLock& c_lock;
public:
	Consumer(CountLock& clock): c_lock(clock) {
	}

	void run() {
		for (int i=0;i<dec_num;i++) c_lock.dec();
	}
};
 
int main()  
{
    CountLock count_lock;
    Producer p(count_lock);
    Consumer c(count_lock);
    std::thread threadP(&Producer::run,&p);
    std::thread threadC(&Consumer::run,&c);
    threadP.join();    
    threadC.join();    
    std::cout<<"after main join count:"<<count_lock.getCount()<<std::endl;
    return 0;
}

atomic

#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>

int inc_num=10001234;
int dec_num=10000000;

class CountLock {
	std::atomic<int> count;
public:
	CountLock() : count(0) {}
	int getCount() 
	{
		return count;
	}
	
	void inc()
	{
		count++;
	}

	void dec()
	{
		count--;
	}
};
 
class Producer
{
	CountLock& c_lock;
public:
	Producer(CountLock& clock): c_lock(clock) {
	}

	void run() {
		for (int i=0;i<inc_num;i++) c_lock.inc();
	}
};

class Consumer
{
	CountLock& c_lock;
public:
	Consumer(CountLock& clock): c_lock(clock) {
	}

	void run() {
		for (int i=0;i<dec_num;i++) c_lock.dec();
	}
};
 
int main()  
{
    CountLock count_lock;
    Producer p(count_lock);
    Consumer c(count_lock);
    std::thread threadP(&Producer::run,&p);
    std::thread threadC(&Consumer::run,&c);
    threadP.join();    
    threadC.join();    
    std::cout<<"after main join count:"<<count_lock.getCount()<<std::endl;
    return 0;
}

0개의 댓글