안녕하세요.
Gamecodi 에 질문을 올렸는데 답이 없어서 여기서 답을 얻을 수 있을지 질문 드립니다.
아래 내용을 보시고 혹시 제가 잘못알고 있는 부분이나 잘못된 코드가 있으면 가르침 부탁 드리겠습니다.
Gamecodi 에 올린 질문 링크:
올린 내용:
Thread 마다 독립된 Map Container 를 사용하려 아래와 같이 하였는데 thread 간에 race condition 이 발생합니다...
사용 방식:
std::vector<Map> g_vec; // std::map 을 element 로 가지고 있는 vector 선언
thread 개수만큼 vector에 비어있는 맵을 미리 할당
0번 thread 는 g_vec[0] 맵만 참조
1번 thread 는 g_vec[1] 만 참조 등등 thread 별로 분리...
구조체 내부에 맵을 선언하고 구조체 배열로 만들어서 사용했을 때는 race condition 문제가 없었는데요. Vector 도 내부적으로 배열이라 알고 있어서 분리된 위치를 참조하기 때문에 race condition 문제가 없을 것으로 봤는데 아닌가 보네요...
이 내용에 대해 알고 계신 분은 설명 좀 부탁 드리겠습니다.
아래는 제가 segment fault 가 발생하는지 확인하려 한 테스트한 코드 입니다.
컴파일 환경 linux gcc, boost 1.50 library 사용
구조체 배열로 확인할 때: g++ -g -O3 -o test vector_of_map_thread.c -lboost_thread -DSTRUCT
vector 로 확인: g++ -g -O3 -o test vector_of_map_thread.c -lboost_thread
OUTPUT 은 vector 에 들어있는 map 들의 size 이며 가끔씩 segment fault 가 발생합니다.
테스트 코드:
#include <boost/thread/thread.hpp>
#include <iostream>
#include <map>
#include <vector>
typedef std::map<int, int> int_map;
#ifdef STRUCT
typedef struct {
int_map map;
} st;
st g_st[5];
#else
std::vector<int_map> g_vec;
#endif
void map_inserter(const int& no)
{
for(int i=0; i<10000000; ++i)
{
#ifdef STRUCT
int_map &m = g_st[no].map;
#else
int_map &m = g_vec[no];
#endif
m.insert(std::pair<int, int>(i,i));
}
}
int main()
{
boost::thread_group threads;
for (int i = 0; i < 5; ++i)
{
#ifndef STRUCT
g_vec.push_back(int_map());
#endif
threads.create_thread(boost::bind(&map_inserter, i));
}
threads.join_all();
#ifdef STRUCT
for(int i=0; i<5; ++i)
std::cout << g_st[i].map.size() << std::endl;
#else
std::vector<int_map>::iterator it;
for(it=g_vec.begin();it!=g_vec.end();++it)
std::cout << it->size() << std::endl;
#endif
}
다 읽진 않았는데 아마 쓰레드의 생성, 소거 시 벡터의 크기를 resize 하는 바람에 realloc 으로 기존의 메모리가 free 되는 문제가 발생한 것일껄?
한 마디로 dangling pointer 가 되었다는거지.
저런 경우 미리 reserve 해서 넉넉히 메모리 공간을 확보해놓고 다루게 되면 별문제 없을것 같은데? 물론 니 취지랑 다르겠지만. ㅋㅋ 동적할당 따위.
Thread 생성 전에 미리 vector 를 채워넣고 하니 crash 가 안나네요. 알려주신 내용 찾아보겠습니다. 감사합니다 ^^
왜 부스트 쓰레드 쓰심? std 쓰레드는 마음에 안 드시는?