본문 바로가기
프로그래밍/boost

boost::atomic & lockfree

by neive 2013. 6. 14.
728x90

 

 

boost_1_53_0 에 드디어 lockfree 정식 등록...

이제 Tim 씨 홈페이지에서 받아서 덮어쓰는 수고를 덜겠군요... Tim 씨 축하합니다 :)

 

예제

 

첫번째 예제. vector 에서 쓰레드 4개로 순차적으로 숫자를 뽑아 사용하고 버렸을 때

ㅎㅎ 해보지 않아도 끔찍하지요.. 돌아갈리가 없습니다

#include "stdafx.h"

#include <Windows.h>

std::vector<int> g_NumList;

void WorkerFunc()
{

	while(true)
	{
		if(!g_NumList.empty())
		{
			int n = g_NumList.back();
			std::cout << boost::format("pop %d ") % n << std::endl;
			g_NumList.pop_back();
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	// init
	for(int i=0; i<100; i++)
		g_NumList.push_back(i);

	// create thread
	boost::thread_group tg;
	tg.create_thread(boost::bind(&WorkerFunc));
	tg.add_thread(new boost::thread(boost::bind(&WorkerFunc)));
	tg.add_thread(new boost::thread(boost::bind(&WorkerFunc)));
	tg.add_thread(new boost::thread(boost::bind(&WorkerFunc)));

	while(g_NumList.size())
	{

	}

	tg.join_all();

	int n;
	std::cin >> n;
	return 0;
}

이번엔 atomic 을 이용한 lock 을 썼습니다. 순서대로 잘 나오지요

#include "stdafx.h"

#include <Windows.h>
#include <boost/atomic.hpp>
#include <boost/thread.hpp>
#include <boost/format.hpp>

class spinlock
{
private:
	typedef enum {Locked, Unlocked} LockState;
	boost::atomic<LockState> state_;

public:
	spinlock() : state_(Unlocked) {}

	void lock()
	{
		while (state_.exchange(Locked, boost::memory_order_acquire) == Locked) {
			/* busy-wait */
		}
	}
	void unlock()
	{
		state_.store(Unlocked, boost::memory_order_release);
	}
};

spinlock g_lock;
std::vector<int> g_NumList;

void WorkerFunc()
{

	while(true)
	{
		g_lock.lock();
		if(!g_NumList.empty())
		{
			int n = g_NumList.back();
			std::cout << boost::format("pop %d ") % n << std::endl;
			g_NumList.pop_back();
		}
		g_lock.unlock();
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	// init
	for(int i=0; i<100; i++)
		g_NumList.push_back(i);

	// create thread
	boost::thread_group tg;
	tg.create_thread(boost::bind(&WorkerFunc));
	tg.add_thread(new boost::thread(boost::bind(&WorkerFunc)));
	tg.add_thread(new boost::thread(boost::bind(&WorkerFunc)));
	tg.add_thread(new boost::thread(boost::bind(&WorkerFunc)));

	while(g_NumList.size())
	{

	}

	tg.join_all();

	int n;
	std::cin >> n;
	return 0;
}

이번엔 lockfree 입니다. atomic 보다는 확실히 쓰기 쉬워 보입니다

#include "stdafx.h"

#include <Windows.h>
#include <boost/lockfree/queue.hpp>
#include <boost/thread.hpp>
#include <boost/format.hpp>

boost::lockfree::queue<int> g_Queue(100);

void WorkerFunc()
{

	while(true)
	{
		int n;
		if(g_Queue.pop(n))
		{
			std::cout << boost::format("pop %d ") % n << std::endl;
		}
		else
			break;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	// init
	for(int i=0; i<100; i++)
		g_Queue.push(i);

	// create thread
	boost::thread_group tg;
	tg.create_thread(boost::bind(&WorkerFunc));
	tg.add_thread(new boost::thread(boost::bind(&WorkerFunc)));
	tg.add_thread(new boost::thread(boost::bind(&WorkerFunc)));
	tg.add_thread(new boost::thread(boost::bind(&WorkerFunc)));

	while(!g_Queue.empty())
	{

	}

	tg.join_all();

	int n;
	std::cin >> n;
	return 0;
}

 

 

atomic 의 결과
 
lockfree 의 결과

 

atomic 은 순서를 엄격하게 지켜지도록 lock 으로 변수의 동시 참조를 막아 쓰레드 처리에 안정성을 갖고

lockfree 는 순서는 엄격하게 지키지 않지만 역시 다른 방식으로 변수의 동시 참조를 막아 쓰레드 처리에 

안정성을 갖게 됩니다. 아래 스샷을 보면 lockfree 쪽은 순서를 엄격하게 지키진 않습니다. 상황에 맞춰서

순서에 상관이 있는 작업인가 없는 작업인가 판단해서 해야할 것 입니다 :)

728x90

'프로그래밍 > boost' 카테고리의 다른 글

boost 라이브러리 설치  (0) 2013.06.12
boost::ptr_unordered_map  (0) 2013.05.24
boost::program_options  (0) 2012.11.16
boost::function / boost::tuple 의 활용  (0) 2012.11.07
boost::tuple / tuples / tuples::tuple  (0) 2012.11.06

댓글