본문 바로가기

ComputerScience/Multi-core Computing

멀티코어컴퓨팅 - 9. C++ Threads

728x90

기본예제

#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
 
void f1(int n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 1 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}
 
void f2(int& n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 2 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}
 
class foo
{
public:
    void bar()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 3 executing\n";
            ++n;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    int n = 0;
};
 
class baz
{
public:
    void operator()()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 4 executing\n";
            ++n;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    int n = 0;
};
 
int main()
{
    int n = 0;
    foo f;
    baz b;
    std::thread t1; // t1 is not a thread
    std::thread t2(f1, n + 1); // pass by value
    std::thread t3(f2, std::ref(n)); // pass by reference
    std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
    std::thread t5(&foo::bar, &f); // t5 runs foo::bar() on object f
    std::thread t6(b); // t6 runs baz::operator() on a copy of object b
    t2.join();
    t4.join();
    t5.join();
    t6.join();
    std::cout << "Final value of n is " << n << '\n';
    std::cout << "Final value of f.n (foo::n) is " << f.n << '\n';
    std::cout << "Final value of b.n (baz::n) is " << b.n << '\n';
}

thread(function, args ...) 로 쓰레드를 생성한다.

쓰레드가 실행되면 func를 수행하고 func가 끝나면 쓰레드는 종료된다.

func에 전달하고 싶은 매개변수는 args에 순서대로 적어준다. 기본적으로는 값이 복사되어 전달된다.

만약 reference를 func에게 전달하고 싶으면 ref()로 감싼다. 

콘솔출력은 순서대로 5, 5, 0이다.

move(t3)을 하면 t4가 t3의 작업을 가져와서 처리한다. t3은 더 이상 쓰레드가 아니다.

java와 달리 .start를 안해도 쓰레드가 생성되면 바로 시작된다.

join()을 호출하면 master thread가 t2, t4, t5, t6을 기다린다.

 

쓰레드 생성 예제

#include <iostream>
#include <thread>

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

        t1.join(); // wait until thread t1 is finished.
        t2.join(); // wait until thread t2 is finished.

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

        return 0;
}

 

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;
}

lock이 없는 counter 프로그램이다.

#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;
}

lock을 적용한 예제이다.

 

Atomic variable

#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;
}
728x90
반응형