Reference page
1. 주요 특징
- count, find, insert, erase 동작은 쓰레드 세이프하다.
- count, find, insert, erase는 기존의 iterator를 무효화시킬 수 있다.
- count, find, insert, erase를 제외한 모든 메써드가 쓰레드 세이프하지 않다.
- 즉, 삽입/삭제가 일어날 수 있는 도중의 이터레이션이 쓰레드 세이프 하지 않다.
- 여러 쓰레드에서의 concurrent access를 위해 accessor라는 녀석을 사용한다.
- accessor는 reader-writer spin lock을 사용하며, find, insert, erase에 사용된다.
map 자료 구조의 주요 동작 (삽입/조회/삭제/순회) 중 순회 기능이 쓰레드 세이프하지 않다.
따라서, 삽입/조회/삭제 뿐 아니라, 이터레이션 역시 주요 기능 중 하나라면, 아쉽지만 락을 사용하는 방식으로 전환해야 한다.
아래 표는 hash_map의 주요 함수들에 대해 쓰레드 세이프 여부에 대해 정리한 것이다.
메서드 | thread_safe | 메서드 | thread_safe | 메서드 | thread_safe |
count | O | find | O | insert | O |
erase | O | get_allocator | X | swap | X |
begin | X | cbegin | X | end | X |
cend | X | equal_range | X | size | X |
max_size | X | empty | X | bucket_count | X |
rehash | X | clear | X |
2. 샘플 코드
- #include <iostream>
- #include <algorithm>
- #include <tbb/parallel_for.h>
- #include <tbb/concurrent_hash_map.h>
- int _tmain(int argc, _TCHAR* argv[])
- {
- tbb::concurrent_hash_map<char, int> map;
- // 멀티쓰레드 환경에서의 삽입 테스트를 위해 parallel_for 사용
- tbb::parallel_for(0, 10, [&] (int i)
- {
- char key = 'a' + (i % 9);
- int value = i;
- // concurrent access를 위해 accessor 사용
- tbb::concurrent_hash_map<char, int>::accessor a;
- // insert시 accessor::lock (spin rw mutex)
- // accessor는 writer lock의 개념
- if (map.insert(a, key))
- {
- a->second = value;
- // a.release();
- }
- // 위에서 a.release()를 명시적으로 호출하지 않아도,
- // accessor는 scoped lock 형태로 구현되어 있기에,
- // 여기에서 accessor가 소멸되면서 암묵적인 accessor::release 수행
- });
- tbb::parallel_for(0, 10, [&] (int i)
- {
- char key = 'a' + (i % 9);
- // const_accessor 사용에 주목
- tbb::concurrent_hash_map<char, int>::const_accessor a;
- // find시 const_accessor::lock (spin rw mutex)
- // const_accessor는 reader lock의 개념
- if (map.find(a, key))
- {
- std::cout << "Found key:" << key << std::endl;
- }
- });
- tbb::parallel_for(0, 10, [&] (int i)
- {
- char key = 'a' + (i % 9);
- tbb::concurrent_hash_map<char, int>::accessor a;
- if (map.erase(key))
- {
- std::cout << "Erased key:" << key << std::endl;
- }
- });
- return 0;
- }