一、概述
在整個(gè)文檔中, Reentrant 和 thread-safe 術(shù)語(yǔ)用于標(biāo)記類和函數(shù),指明如何在多線程應(yīng)用程序中使用它們:
- 一個(gè) thread-safe的函數(shù)可以從多個(gè)線程同時(shí)調(diào)用,即使調(diào)用使用了共享數(shù)據(jù),因?yàn)閷?duì)共享數(shù)據(jù)的所有引用都是序列化的。
- 一個(gè) Reentrant 函數(shù)也可以從多個(gè)線程同時(shí)調(diào)用Reentrant函數(shù),但前提是每次調(diào)用都使用自己的數(shù)據(jù)。
因此,thread-safe 的函數(shù)總是Reentrant的,但 Reentrant 的函數(shù)并不總是線程安全的,可以理解Reentrant 是線程不安全的。
擴(kuò)展一下,如果一個(gè)類的成員函數(shù)可以在多個(gè)線程中安全地調(diào)用,只要每個(gè)線程使用這個(gè)類的不同實(shí)例,那么這個(gè)類就是Reentrant的。如果類的成員函數(shù)可以在多個(gè)線程中安全地調(diào)用,那么這個(gè)類就是線程安全的,即使所有線程都使用這個(gè)類的同一個(gè)實(shí)例。
注意:Qt類只有在被多個(gè)線程使用時(shí)才被記錄為線程安全的。如果函數(shù)未標(biāo)記為線程安全或Reentrant,則不應(yīng)在不同的線程中使用它。如果類未標(biāo)記為線程安全或Reentrant,則不應(yīng)從不同線程訪問(wèn)該類的特定實(shí)例。
二、Reentrant
c++類通常是Reentrant的,因?yàn)樗鼈冎辉L問(wèn)自己的成員數(shù)據(jù)。任何線程都可以調(diào)用Reentrant類實(shí)例的成員函數(shù),只要其他線程不能同時(shí)調(diào)用同一個(gè)類實(shí)例的成員函數(shù)。例如,下面的Counter類是Reentrant的:
class Counter
{
public:
Counter() { n = 0; }
void increment() { ++n; }
void decrement() { --n; }
int value() const { return n; }
private:
int n;
};
這個(gè)類不是線程安全的,因?yàn)槿绻鄠€(gè)線程試圖修改數(shù)據(jù)成員n,結(jié)果是未定義的。這是因?yàn)?++ 和 – 操作符并不總是原子的。實(shí)際上,它們通常擴(kuò)展為3條機(jī)器指令:
- 將變量的值加載到寄存器中。
- 增加或減少寄存器的值。
- 將寄存器的值存儲(chǔ)到主內(nèi)存中。
如果線程A和線程B同時(shí)加載變量的舊值,增加它們的寄存器并存儲(chǔ)它,它們最終會(huì)相互覆蓋,變量只會(huì)增加一次!
三、線程安全
顯然,訪問(wèn)必須序列化:線程A必須不間斷地(原子操作的)執(zhí)行步驟1、2、3,然后線程B才能執(zhí)行相同的步驟;反之亦然。讓類成為線程安全的一種簡(jiǎn)單方法是使用QMutex來(lái)保護(hù)對(duì)數(shù)據(jù)成員的所有訪問(wèn):
class Counter
{
public:
Counter() { n = 0; }
void increment() { QMutexLocker locker(&mutex); ++n; }
void decrement() { QMutexLocker locker(&mutex); --n; }
int value() const { QMutexLocker locker(&mutex); return n; }
private:
mutable QMutex mutex;
int n;
};
QMutexLocker類會(huì)在構(gòu)造函數(shù)中自動(dòng)鎖定互斥量,并在函數(shù)末尾調(diào)用析構(gòu)函數(shù)時(shí)解鎖。鎖定互斥量可以確保來(lái)自不同線程的訪問(wèn)將被序列化?;コ饬繑?shù)據(jù)成員使用可變限定符聲明,因?yàn)槲覀冃枰趘alue()中鎖定和解鎖互斥量,這是一個(gè)const函數(shù)。
四、Qt類的注意事項(xiàng)
許多Qt類是Reentrant的,但它們不是線程安全的,因?yàn)槭顾鼈兂蔀榫€程安全的會(huì)導(dǎo)致重復(fù)鎖定和解鎖QMutex的額外開(kāi)銷(xiāo)。例如,QString是Reentrant的,但不是線程安全的。你可以從多個(gè)線程同時(shí)安全地訪問(wèn)不同的QString實(shí)例,但你不能從多個(gè)線程同時(shí)安全地訪問(wèn)同一個(gè)QString實(shí)例(除非你自己使用QMutex來(lái)保護(hù)訪問(wèn))。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-422621.html
有些Qt類和函數(shù)是線程安全的。這些主要是線程相關(guān)的類(例如QMutex)和基本函數(shù)(例如QCoreApplication::postEvent())。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-422621.html
- 注意:多線程領(lǐng)域的術(shù)語(yǔ)并沒(méi)有完全標(biāo)準(zhǔn)化。POSIX使用的Reentrant和線程安全的定義與其C api有些不同。當(dāng)在Qt中使用其他面向?qū)ο蟮腸++類庫(kù)時(shí),請(qǐng)確保理解這些定義。
到了這里,關(guān)于Qt掃盲-Reentrant和線程安全的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!