和許多客戶端程序一樣,chromium中同樣使用到了多線程,每個線程可能包括一個消息循環MessageLoop,它通過調用current函數返回,因爲MessageLoop是線程的私有數據,線程內共享而線程間不共享,這就使用到了線程局部存儲(Thread Local Storage,TLS)技術。TLS技術在不同的操作系統中通過不同的系統調用實現,它爲線程提供一種保存私有數據的方法,使線程的私有數據對其它線程不可見。chromium通過定義模版類ThreadLocalPointer實現線程私有的數據指針。以下是ThreadLocalPointer的實現
template <typename Type>
class ThreadLocalPointer {
public:
ThreadLocalPointer() : slot_() {
internal::ThreadLocalPlatform::AllocateSlot(&slot_);
}
~ThreadLocalPointer() {
internal::ThreadLocalPlatform::FreeSlot(slot_);
}
Type* Get() {
return static_cast<Type*>(
internal::ThreadLocalPlatform::GetValueFromSlot(slot_));
}
void Set(Type* ptr) {
internal::ThreadLocalPlatform::SetValueInSlot(
slot_, const_cast<void*>(static_cast<const void*>(ptr)));
}
private:
typedef internal::ThreadLocalPlatform::SlotType SlotType;
SlotType slot_;
DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer<Type>);
};
對於不同的操作系統,TLS的實現方式並不相同,所以在實現過程中定久了接口類ThreadLocalPlatform,它定義了TLS的一些基本操作,對於不同的操作系統,只需要對接口進行實現就可以了。例如,在windows下的實現爲:
void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
*slot = TlsAlloc();
CHECK_NE(*slot, TLS_OUT_OF_INDEXES);
}
// static
void ThreadLocalPlatform::FreeSlot(SlotType slot) {
if (!TlsFree(slot)) {
NOTREACHED() << "Failed to deallocate tls slot with TlsFree().";
}
}
// static
void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
return TlsGetValue(slot);
}
// static
void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
if (!TlsSetValue(slot, value)) {
LOG(FATAL) << "Failed to TlsSetValue().";
}
}
在實現中可以看出,當 ThreadLocalPointer構造的時候,由操作系統分配出一個slot_,通過slot_可以取出保存和讀取特定的數據,在 ThreadLocalPointer中,這個數據的類型就是一個指針。
這樣說明還是很不容易理解TLS的原理,其實可以理解成操作系統爲每一個線程都分配了一個大小相同的數組TLS_ARRAY,當調用TlsAlloc時,系統遍歷所有的線程,找到一個slot_,在所有線程中TLS_ARRAY[slot_]都爲空,slot_值就相當於一個索引保存下來。當某一個線程要設置私有數據時,操作系統會根據slot_值找到線程私有的數據TLS_ARRAY[slot_],用戶可以設置它的值或者調取它的值。
當ThreadLocalPointer析構的時候,會調用TlsFree釋放slot_,這是所有數據中TLS_ARRAY[slot_]的值都置爲了空。