工作中用到过一些tbb,不过面试的时候别人一问就傻了,所以复习一下TBB的文档,并系统学习一下多线程编程。
1) TBB container
tbb容器中用到的concurrency支持技术:
• Fine-grainedlocking: Multiple threads operate on the container by locking only
those portions they really need to lock. As long as different threads access
different portions, they can proceed concurrently.
• Lock-free techniques: Different threads account and correct for the effectsof
other interfering threads.
第一个还好理解, 第二种技术比较复杂 Lock-free 需要阅读一些相关的文章
2) TBB mutex
Mutex 定义 :Mutex is anobject on which a thread can acquire a lock. Only one threadat a time can havea lock on a mutex.
关于spin_mutex : Thesimplestmutex is spin_mutex. A thread trying to acquire a lock on a spin_mutexbusywaits until it can acquire the lock.
Mutex使用示例:
Node* FreeList;
typedef spin_mutexFreeListMutexType;
FreeListMutexTypeFreeListMutex;
Node* AllocateNode(){
Node* n;
{
FreeListMutexType::scoped_locklock(FreeListMutex);
n = FreeList;
if (n)
FreeList = n->next;
}
if (!n)
n = new Node();
return n;
}
void FreeNode(Node*n) {
FreeListMutexType::scoped_locklock(FreeListMutex);
n->next = FreeList;
FreeList = n;
}
scoped_lock 的构造函数等待其他的线程不再lock住FreeListMutex。析构函数release掉这个lock。 AllocatedNode中的花括号是为了让lock的生命周期尽量的短。
注意事项: 对lock对象命名,否则它很快就会被析构。举个例子
FreeListMutexType::scoped_lock(FreeListMutex);
这会导致scoped_lock对象在行尾被析构掉,这就会导致在访问FreeList之前Lock就被释放掉了。
TIPS: 推荐使用 typedef 来声明mutex类型,这样方面修改mutex的类型.
3) reader/writer mutexes 及 upgrade_to_writer
当一个线程对一个共享变量进行写操作时,互斥是必须的。但是我们可以允许多个读操作进入保护区域。Reader-writer mutexes通过区分reader lock和writer lock允许多个读线程。
对reader lock的获取可以通过传递一个bool变量给scoped_lock的构造函数来生成。
例程:
std::vector<string> MyVector;
typedef spin_rw_mutex MyVectorMutexType;
MyVectorMutexType MyVectorMutex;
void AddKeyIfMissing( const string& key ) {
// Obtain a reader lock on MyVectorMutex
MyVectorMutexType::scoped_lock
lock(MyVectorMutex,/*is_writer=*/false);
size_t n = MyVector.size();
for( size_t i=0; i<n; ++i )
if( MyVector[i]==key ) return;
if( !lock.upgrade_to_writer() )
// Check if key was added while lock was temporarily released
for( int i=n; i<MyVector.size(); ++i )
if(MyVector[i]==key ) return;
vector.push_back(key);
}
上面的例子在push_back操作时再做一次检查,是因为upgrade_to_writer操作会在upgrade之前临时释放掉lock,这个时间点其他的writer线程可能对vector进行了操作。
4) 避免死锁
方法:
1) 避免同时需求多个lock.
2) 在请求lock时,按照固定相同的顺序
3) 使用原子操作