當前位置:首頁 » 存儲配置 » 線程局部存儲tls

線程局部存儲tls

發布時間: 2023-05-21 04:10:54

linuxC++如何編寫線程安全庫

LinuxC++編寫線程安全庫dll的方法:
1、動態庫只有一個導出函數。
這種情況下編寫函數時,只需要考慮不要有沖突的全局數據就可以了。這里的全局數據包括了在堆中分配的數據塊和靜態全局變數等。如果存在這樣的全局數據,那麼進程中的不同線程訪問這個函數就會造成沖突。
2、動態庫導出了多個函數,而且多個函數間存在數據傳遞。
一般DLL都導出多個函數,一個初始化,一個資源釋放,其他為核心功能函數。這些函數間極有可能發生數據傳遞。如果一個初始化函數是在線程A中調用的,而核心功能函數是在線程B中調用的,那麼線程A初始化函數的資源就無法對應線程B中的核心功能,此外還有核心功能函數間的數據傳遞,這樣的DLL就不是線程安全的,必然導致錯誤。
解決辦法是由用戶(即使用DLL的人)保證這些導出函數是在一個線程中調用。但這樣會很大程度上限制介面的設計和用戶的使用自由度。所以最好的方法是函數只管自己的線程安全,不同函數傳遞數據用動態TLS,線程局部存儲
3、限制訪問DLL中某一函數的線程數目。
對於DLL中的某一個函數的訪問線程數目是有限制的,超過了限制其他線程就得等一定的時間,一定的時間過後如果還不能得到執行機會,那就返回超時。這樣的設計對用戶來說是友好的,而且很實用,有的商業程序確實是按照允許用戶訪問的通道數目來計價的。
對DLL中的函數做這樣的一個封裝,一般是簡單的待用Semaphore信號量,來解決。DLL初始化時調用CreateSemaphore函數對信號量進行初始化,其原型如下:
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
// pointer to security attributes
LONG lInitialCount, // initial count
LONG lMaximumCount, // maximum count
LPCTSTR lpName // pointer to semaphore-object name
);
對於信號量,它每WaitForSingleObject一次(當然是要進入),其狀態值(一個整數)就減1,使用完ReleaseSemaphore其狀態值就加1,當其狀態值為0時信號量就由有信號變為無信號。利用信號量的這一特性,我們在初始化時將信號量的初始值(第2個參數)設置為限制的線程訪問數目。在要限制訪問線程數目的函數內部,通過調用WaitForSingleOject獲取控制權,並指定一個等待時間(這個由配置文件指定),根據情況超時返回,使用完ReleaseSemaphore釋放對佔用,讓其他線程可以調用這個函數。
4、多進程情況下的多線程安全DLL。
LL是可以被多個進行載入並調用的。那就是說如果我們只對一個進程進行了限制,那麼在多進程調用的情況下,這樣的限制被輕易攻破。
我們都知道,Semaphore信號量屬於內核對象,也就是說其可以被多進程共享訪問,也就說,如果我們給一個Semaphore指定了一個名字,在另一個進程中,我們只要調用OpenSemaphore函數用同一名字打開信號量就可以訪問了。這樣問題就解決了?
現實情況是,多進程情況下,一般不是簡單的多進程共享一個Semaphore就可以了。多進程間需要互通很多信息。一般的解決辦法是,採用共享數據段。
#pragma data_seg("share")
int share_data;
#pragma data_seg()
#pragma comment(linker,"/SECTION:share, RWS")
通過pragam編譯器指令生成了一個名叫share的共享數據段,這樣對於變數share_data就可以多進程共享的了。如果要多進程間交換數據,只要在data_seg中添加數據定義即可。

Ⅱ 線程的線程的同步

線程的同步是Java多線程編程的難點,往往開發者搞不清楚什麼是競爭資源、什麼時候需要考慮同步,怎麼同步等等問題,當然,這些問題沒有很明確的答案,但有些原則問題需要考慮,是否有競爭資源被同時改動的問題?對於同步,在具體的Java代碼中需要完成以下兩個操作:把競爭訪問的資源標識為private;同步哪些修改變數的代碼,使用synchronized關鍵字同步方法或代碼。當然這不是唯一控制並發安全的途徑。synchronized關鍵字使用說明synchronized只能標記非抽象的方法,不能標識成員變數。為了演示同步方法的使用,構建了一個信用卡賬戶,起初信用額為100w,然後模擬透支、存款等多個操作。顯然銀行賬戶User對象是個競爭資源,而多個並發操作的是賬戶方法oper(int x),當然應該在此方法上加上同步,並將賬戶的余額設為私有變數,禁止直接訪問。
工作原理
線程是進程中的實體,一個進程可以擁有多個線程,一個線程必須有一個父進程。線程不擁有系統資源,只有運行必須的一些數據結構;它與父進程的其它線程共享該進程所擁有的全部資源。線程可以創建和撤消線程,從而實現程序的並發執行。一般,線程具有就緒、阻塞和運行三種基本狀態。
在多中央處理器的系統里,不同線程可以同時在不同的中央處理器上運行,甚至當它們屬於同一個進程時也是如此。大多數支持多處理器的操作系統都提供編程介面來讓進程可以控制自己的線程與各處理器之間的關聯度(affinity)。
有時候,線程也稱作輕量級進程。就象進程一樣,線程在程序中是獨立的、並發的執行路徑,每個線程有它自己的堆棧、自己的程序計數器和自己的局部變數。但是,與分隔的進程相比,進程中的線程之間的隔離程度要小。它們共享內存、文件句柄和其它每個進程應有的狀態。
進程可以支持多個線程,它們看似同時執行,但互相之間並不同步。一個進程中的多個線程共享相同的內存地址空間,這就意味著它們可以訪問相同的變數和對象,而且它們從同一堆中分配對象。盡管這讓線程之間共享信息變得更容易,但您必須小心,確保它們不會妨礙同一進程里的其它線程。
Java 線程工具和 API看似簡單。但是,編寫有效使用線程的復雜程序並不十分容易。因為有多個線程共存在相同的內存空間中並共享相同的變數,所以您必須小心,確保您的線程不會互相干擾。
線程屬性
為了正確有效地使用線程,必須理解線程的各個方面並了解Java 實時系統。必須知道如何提供線程體、線程的生命周期、實時系統如 何調度線程、線程組、什麼是幽靈線程(Demo nThread)。
線程體
所有的操作都發生在線程體中,在Java中線程體是從Thread類繼承的run()方法,或實現Runnable介面的類中的run()方法。當線程產生並初始化後,實時系統調用它的run()方法。run()方法內的代碼實現所產生線程的行為,它是線程的主要部分。
線程狀態
附圖表示了線程在它的生命周期內的任何時刻所能處的狀態以及引起狀態改變的方法。這圖並不是完整的有限狀態圖,但基本概括了線程中比較感興趣和普遍的方面。以下討論有關線程生命周期以此為據。
●新線程態(New Thread)
產生一個Thread對象就生成一個新線程。當線程處於新線程狀態時,僅僅是一個空線程對象,它還沒有分配到系統資源。因此只能啟動或終止它。任何其他操作都會引發異常。例如,一個線程調用了new方法之後,並在調用start方法之前的處於新線程狀態,可以調用start和stop方法。
●可運行態(Runnable)
start()方法產生運行線程所必須的資源,調度線程執行,並且調用線程的run()方法。在這時線程處於可運行態。該狀態不稱為運行態是因為這時的線程並不總是一直佔用處理機。特別是對於只有一個處理機的PC而言,任何時刻只能有一個處於可運行態的線程佔用處理 機。Java通過調度來實現多線程對處理機的共享。注意,如果線程處於Runnable狀態,它也有可能不在運行,這是因為還有優先順序和調度問題。
●阻塞/非運行態(Not Runnable)
當以下事件發生時,線程進入非運行態。

①suspend()方法被調用;
②sleep()方法被調用;
③線程使用wait()來等待條件變數;
④線程處於I/O請求的等待。
●死亡態(Dead)
當run()方法返回,或別的線程調用stop()方法,線程進入死亡態。通常Applet使用它的stop()方法來終止它產生的所有線程。
線程的本操作:
派生:線程在進程內派生出來,它即可由進程派生,也可由線程派生。
阻塞(Block):如果一個線程在執行過程中需要等待某個事件發生,則被阻塞。
激活(unblock):如果阻塞線程的事件發生,則該線程被激活並進入就緒隊列。
調度(schele):選擇一個就緒線程進入執行狀態。
結束(Finish):如果一個線程執行結束,它的寄存器上下文以及堆棧內容等將被釋放。
圖2 線程的狀態與操作
線程的另一個執行特性是同步。線程中所使用的同步控制機制與進程中所使用的同步控制機制相同。
線程優先順序
雖然我們說線程是並發運行的。然而事實常常並非如此。正如前面談到的,當系統中只有一個CPU時,以某種順序在單CPU情況下執行多線程被稱為調度(scheling)。Java採用的是一種簡單、固定的調度法,即固定優先順序調度。這種演算法是根據處於可運行態線程的相對優先順序來實行調度。當線程產生時,它繼承原線程的優先順序。在需要時可對優先順序進行修改。在任何時刻,如果有多條線程等待運行,系統選擇優先順序最高的可運行線程運行。只有當它停止、自動放棄、或由於某種原因成為非運行態低優先順序的線程才能運行。如果兩個線程具有相同的優先順序,它們將被交替地運行。Java實時系統的線程調度演算法還是強制性的,在任何時刻,如果一個比其他線程優先順序都高的線程的狀態變為可運行態,實時系統將選擇該線程來運行。一個應用程序可以通過使用線程中的方法setPriority(int),來設置線程的優先順序大小。
有線程進入了就緒狀態,需要有線程調度程序來決定何時執行,根據優先順序來調度。
線程中的join()可以用來邀請其他線程先執行(示例代碼如下):
packageorg.thread.test;{publicstaticvoidmain(String[]args){for(inti=0;i<20;i++){if(i==5){Join01j=newJoin01();Threadt=newThread(j);t.setName(被邀請先執行的線程.);t.start();try{//邀請這個線程,先執行t.join();}catch(InterruptedExceptione){e.printStackTrace();}}System.out.println(沒被邀請的線程。+(i+1));}}publicvoidrun(){for(inti=0;i<10;i++){System.out.println(Thread.currentThread().getName()+(i+1));}}}
yield()告訴系統把自己的CPU時間讓掉,讓其他線程或者自己運行,示例代碼如下:
packageorg.thread.test;
publicclassYield01
{
publicstaticvoidmain(String[]args)
{
YieldFirstyf=newYieldFirst();
YieldSecondys=newYieldSecond();
YieldThirdyt=newYieldThird();
yf.start();ys.start();yt.start();
}
}
classYieldFirstextendsThread
{
@Overridepublicvoidrun()
{
for(inti=0;i<10;i++)
{
System.out.println(第一個線程第+(i+1)+次運行.);//讓當前線程暫停yield();
}
}
}
classYieldSecondextendsThread
{
@Overridepublicvoidrun()
{
for(inti=0;i<10;i++)
{
System.out.println(第二個線程第+(i+1)+次運行.);//讓當前線程暫停yield();
<a href=mailto:}}}classYieldThirdextendsThread{@Overridepublicvoidrun(){for(inti=0;i}
}
}
classYieldThirdextendsThread
{
@Overridepublicvoidrun(){for(inti=0;i<10;i++)
{
System.out.println(第三個線程第+(i+1)+次運行.);//讓當前線程暫停yield();
}
}
幽靈線程
任何一個Java線程都能成為幽靈線程。它是作為運行於同一個進程內的對象和線程的服務提供者。例如,HotJava瀏覽器有一個稱為 後台圖片閱讀器的幽靈線程,它為需要圖片的對象和線程從文件系統或網路讀入圖片。幽靈線程是應用中典型的獨立線程。它為同一應用中的其他對象和線程提供服務。幽靈線程的run()方法一般都是無限循環,等待服務請求。
線程組
每個Java線程都是某個線程組的成員。線程組提供一種機制,使得多個線程集於一個對象內,能對它們實行整體操作。譬如,你能用一個方法調用來啟動或掛起組內的所有線程。Java線程組由ThreadGroup類實現。
當線程產生時,可以指定線程組或由實時系統將其放入某個預設的線程組內。線程只能屬於一個線程組,並且當線程產生後不能改變它所屬的線程組。
多線程
對於多線程的好處這就不多說了。但是,它同樣也帶來了某些新的麻煩。只要在設計程序時特別小心留意,克服這些麻煩並不算太困難。在生成線程時必須將線程放在指定的線程組,也可以放在預設的線程組中,預設的就是生成該線程的線程所在的線程組。一旦一個線程加入了某個線程組,不能被移出這個組。
同步線程
許多線程在執行中必須考慮與其他線程之間共享數據或協調執行狀態。這就需要同步機制。在Java中每個對象都有一把鎖與之對應。但Java不提供單獨的lock和unlock操作。它由高層的結構隱式實現,來保證操作的對應。(然而,我們注意到Java虛擬機提供單獨的monito renter和monitorexit指令來實現lock和
unlock操作。) synchronized語句計算一個對象引用,試圖對該對象完成鎖操作,並且在完成鎖操作前停止處理。當鎖操作完成synchronized語句體得到執行。當語句體執行完畢(無論正常或異常),解鎖操作自動完成。作為面向對象的語言,synchronized經常與方法連用。一種比較好的辦法是,如果某個變數由一個線程賦值並由別的線程引用或賦值,那麼所有對該變數的訪問都必須在某個synchromized語句或synchronized方法內。
現在假設一種情況:線程1與線程2都要訪問某個數據區,並且要求線程1的訪問先於線程2,則這時僅用synchronized是不能解決問題的。這在Unix或Windows NT中可用Simaphore來實現。而Java並不提供。在Java中提供的是wait()和notify()機制。使用如下:
synchronizedmethod_1(/*……*/){//calledbythread1.//accessdataareaavailable=true;notify();}synchronizedmethod_2(/*……*/){//calledbythread2.while(!available)try{wait();//waitfornotify().}catch(InterruptedExceptione){}//accessdataarea}
其中available是類成員變數,置初值為false。
如果在method-2中檢查available為假,則調用wait()。wait()的作用是使線程2進入非運行態,並且解鎖。在這種情況下,method-1可以被線程1調用。當執行notify()後。線程2由非運行態轉變為可運行態。當method-1調用返回後。線程2可重新對該對象加鎖,加鎖成功後執行wait()返回後的指令。這種機制也能適用於其他更復雜的情況。
死鎖
如果程序中有幾個競爭資源的並發線程,那麼保證均衡是很重要的。系統均衡是指每個線程在執行過程中都能充分訪問有限的資源。系統中沒有餓死和死鎖的線程。Java並不提供對死鎖的檢測機制。對大多數的Java程序員來說防止死鎖是一種較好的選擇。最簡單的防止死鎖的方法是對競爭的資源引入序號,如果一個線程需要幾個資源,那麼它必須先得到小序號的資源,再申請大序號的資源。
優化
Java的多線程安全是基於Lock機制實現的,而Lock的性能往往不如人意。原因是,monitorenter與monitorexit這兩個控制多線程同步的bytecode原語,是JVM依賴操作系統互斥(mutex)來實現的。而互斥是一種會導致線程掛起,並在較短的時間內又需要重新調度回原線程的,較為消耗資源的操作。所以需要進行對線程進行優化,提高效率。
輕量級鎖
輕量級鎖(Lightweight Locking)是從Java6開始引入的概念,本意是為了減少多線程進入互斥的幾率,並不是要替代互斥。它利用了CPU原語Compare-And-Swap(CAS,匯編指令CMPXCHG),嘗試在進入互斥前,進行補救。下面將詳細介紹JVM如何利用CAS,實現輕量級鎖。
Java Object Model中定義,Object Header是一個2字(1 word = 4 byte)長度的存儲區域。第一個字長度的區域用來標記同步,GC以及hash code等,官方稱之為 mark word。第二個字長度的區域是指向到對象的Class。在2個word中,mark word是輕量級鎖實現的關鍵,其結構見右表。
從表中可以看到,state為lightweight locked的那行即為輕量級鎖標記。bitfieds名為指向lock record的指針,這里的lock record,其實是一塊分配在線程堆棧上的空間區域。用於CAS前,拷貝object上的mark word。第三項是重量級鎖標記。後面的狀態單詞很有趣,inflated,譯為膨脹,在這里意思其實是鎖已升級到OS-level。一般我們只關注第二和第三項即可。lock,unlock與mark word之間的聯系如右圖所示。在圖中,提到了拷貝object mark word,由於脫離了原始mark word,官方將它冠以displaced前綴,即displaced mark word(置換標記字)。這個displaced mark word是整個輕量級鎖實現的關鍵,在CAS中的compare就需要用它作為條件。
在拷貝完object mark word之後,JVM做了一步交換指針的操作,即流程中第一個橙色矩形框內容所述。將object mark word里的輕量級鎖指針指向lock record所在的stack指針,作用是讓其他線程知道,該object monitor已被佔用。lock record里的owner指針指向object mark word的作用是為了在接下里的運行過程中,識別哪個對象被鎖住了。
最後一步unlock中,我們發現,JVM同樣使用了CAS來驗證object mark word在持有鎖到釋放鎖之間,有無被其他線程訪問。如果其他線程在持有鎖這段時間里,嘗試獲取過鎖,則可能自身被掛起,而mark word的重量級鎖指針也會被相應修改。此時,unlock後就需要喚醒被掛起的線程。
偏向鎖
Java偏向鎖(Biased Locking)是Java 6引入的一項多線程優化。它通過消除資源無競爭情況下的同步原語,進一步提高了程序的運行性能。它與輕量級鎖的區別在於,輕量級鎖是通過CAS來避免進入開銷較大的互斥操作,而偏向鎖是在無競爭場景下完全消除同步,連CAS也不執行(CAS本身仍舊是一種操作系統同步原語,始終要在JVM與OS之間來回,有一定的開銷)。所謂的無競爭場景,就是單線程訪問帶同步的資源或方法。
偏向鎖,顧名思義,它會偏向於第一個訪問鎖的線程,如果在接下來的運行過程中,該鎖沒有被其他的線程訪問,則持有偏向鎖的線程將永遠不需要觸發同步。如果在運行過程中,遇到了其他線程搶占鎖,則持有偏向鎖的線程會被掛起,JVM會嘗試消除它身上的偏向鎖,將鎖恢復到標準的輕量級鎖。(偏向鎖只能在單線程下起作用)。
偏向模式和非偏向模式,在mark word表中,主要體現在thread ID欄位是否為空。
掛起持有偏向鎖的線程,這步操作類似GC的pause,但不同之處是,它只掛起持有偏向鎖的線程(非當前線程)。
在搶占模式的橙色區域說明中有提到,指向當前堆棧中最近的一個lock record(在輕量級鎖中,lock record是進入鎖前會在stack上創建的一份內存空間)。這里提到的最近的一個lock record,其實就是當前鎖所在的stack frame上分配的lock record。整個步驟是從偏向鎖恢復到輕量級鎖的過程。
偏向鎖也會帶來額外開銷。在JDK6中,偏向鎖是默認啟用的。它提高了單線程訪問同步資源的性能。
但試想一下,如果你的同步資源或代碼一直都是多線程訪問的,那麼消除偏向鎖這一步驟對你來說就是多餘的。事實上,消除偏向鎖的開銷還是蠻大的。所以在你非常熟悉自己的代碼前提下,大可禁用偏向鎖 -XX:-UseBiasedLocking。
分類
線程有兩個基本類型:
用戶級線程:管理過程全部由用戶程序完成,操作系統內核心只對進程進行管理。
系統級線程(核心級線程):由操作系統內核進行管理。操作系統內核給應用程序提供相應的系統調用和應用程序介面API,以使用戶程序可以創建、執行、撤消線程。
舉例UNIX International 線程
UNIX International 線程的頭文件是<thread.h> ,僅適用於Sun Solaris操作系統。所以UNIX International線程也常被俗稱為Solaris線程。
1.創建線程
intthr_create(void*stack_base,size_tstack_size,void*(*start_routine)(void*),void*arg,longflags,thread_t*new_thr);
2.等待線程
intthr_join(thread_twait_for,thread_t*dead,void**status);
3.掛起線程
intthr_suspend(thread_tthr);
4.繼續線程
intthr_continue(thread_tthr);
5.退出線程
voidthr_exit(void*status);
6.返回當前線程的線程標識符
thread_tthr_self(void);POSIX線程
POSIX線程(Pthreads)的頭文件是<pthread.h>,適用於類Unix操作系統。Windows操作系統並沒有對POSIX線程提供原生的支持庫。不過Win32的POSIX線程庫的一些實現也還是有的,例如pthreads-w32 。
1.創建線程
intpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*arg);
2.等待線程
intpthread_join(pthread_tthread,void**retval);
3.退出線程
voidpthread_exit(void*retval);
4.返回當前線程的線程標識符
pthread_tpthread_self(void);
5.線程取消
intpthread_cancel(pthread_tthread);Win32線程
Win32線程的頭文件是<Windows.h>,適用於Windows操作系統。
1.創建線程
HANDLEWINAPICreateThread(LPSECURITY_ATTRIBUTESlpThreadAttributes,SIZE_TdwStackSize,LPTHREAD_START_ROUTINElpStartAddress,LPVOIDlpParameter,DWORDdwCreationFlags,LPDWORDlpThreadId);
2.結束本線程
VOIDWINAPIExitThread(DWORDdwExitCode);
3.掛起指定的線程
DWORDWINAPISuspendThread(HANDLEhThread);
4.恢復指定線程運行
DWORDWINAPIResumeThread(HANDLEhThread);
5.等待線程運行完畢
(HANDLEhHandle,DWORDdwMilliseconds);
6.返回當前線程的線程標識符
DWORDWINAPIGetCurrentThreadId(void);
7.返回當前線程的線程句柄
HANDLEWINAPIGetCurrentThread(void);C++ 11 線程
C++ 11 線程的頭文件是<thread>。 創建線程
std::thread::thread(Function&& f, Args&&... args); 等待線程結束
std::thread::join(); 脫離線程式控制制
std::thread::detach(); 交換線程
std::thread::swap( thread& other ); C 11 線程
C11線程的頭文件是<threads.h>。
C11線程僅僅是個「建議標准」,也就是說100%遵守C11標準的C編譯器是可以不支持C11線程的。根據C11標準的規定,只要編譯器預定義了__STDC_NO_THREADS__宏,就可以沒有<threads.h>頭文件,自然也就也沒有下列函數。
1.創建線程
intthrd_create(thrd_t*thr,thrd_start_tfunc,void*arg);
2.結束本線程
_Noreturnvoidthrd_exit(intres);
3.等待線程運行完畢
intthrd_join(thrd_tthr,int*res);
4.返回當前線程的線程標識符
thrd_tthrd_current();Java線程
1)最簡單的情況是,Thread/Runnable的run()方法運行完畢,自行終止。
2)對於更復雜的情況,比如有循環,則可以增加終止標記變數和任務終止的檢查點。
3)最常見的情況,也是為了解決阻塞不能執行檢查點的問題,用中斷來結束線程,但中斷只是請求,並不能完全保證線程被終止,需要執行線程協同處理。
4)IO阻塞和等鎖情況下需要通過特殊方式進行處理。
5)使用Future類的cancel()方法調用。
6)調用線程池執行器的shutdown()和shutdownNow()方法。
7)守護線程會在非守護線程都結束時自動終止。
8)Thread的stop()方法,但已不推薦使用。
線程的組成
1)一組代表處理器狀態的CPU寄存器中的內容
2)兩個棧,一個用於當線程在內核模式下執行的時候,另一個用於線程在用戶模式下執行的時候
3)一個被稱為線程局部存儲器(TLS,thread-local storage)的私有儲存區域,各個子系統、運行庫和DLL都會用到該儲存區域
4)一個被稱為線程ID(thread ID,線程標識符)的唯一標識符(在內部也被稱為客戶ID——進程ID和線程ID是在同一個名字空間中生產的,所以它們永遠 不會重疊)
5)有時候線程也有它們自己的安全環境,如果多線程伺服器應用程序要模仿其客戶的安全環境,則往往可以利用線程的安全環境

Ⅲ 有MSVC編譯器的命令行大全么

1 cl,MSVC編譯器
/c:只編譯鏈接
/Za:禁止語言擴展
/link:鏈接指定的模塊或給鏈接器傳遞參數
/Od:禁止優化
/O2:以允許速度最快為目標優化
/O1:以最節省空間為目標優化
/GR或/GR-:開啟或關閉RTTI
/Gy:開啟函數級別鏈接
/GS或/GS-:開啟或關閉
/Fa:輸出匯編文件
/E:只進行預處理並且把結果輸出
/I:指定頭文件包含目錄
/Zi:啟用調試信息
/LD:編譯產生DLL文件
/LDd:編譯產生DLL文件(調試版)
/MD:與動態多線程版本運行庫MSVCRT.LIB鏈接
/MDd:與調試版動態多線程版本運行庫MSVCRTD.LIB鏈接
/MT:與靜態多線程版本運行庫LIBCMT.LIB鏈接
/MTd:與調試版靜態多線程版本運行庫LIBCMTD.LIB鏈接
2 link,MSVC鏈接器
/BASE:address:指定輸出文件的基地址
/DEBUG:輸出調試模式版本
/DEF:filename:指定模塊定義文件.DEF
/DEFAULTLIB:library:指定默認運行庫
/DLL:產生DLL
/ENTRY:symbol:指定程序路口
/EXPORT:symbol:指定某個符號位導出符號
/HEAP:指定默認堆大小
/LIBPATH:dir:指定鏈接時庫搜索路徑
/MAP:產生鏈接MAP文件
/NODEFAULTLIB:禁止默認運行庫
/OUT:指定輸出文件名
/RELEASE:已發布版本產生輸出文件
/STACK:指定默認棧大小
/SUBSYSTEM:指定子系統
3 mpbin,MSVC的COFF/PE文件查看器
/ALL:顯示所有信息
/ARCHIVEMEMBERS:顯示LIB文件中的所有目標文件列表
/DEPENDENTS:顯示文件的動態鏈接依賴關系
/DIRECTIVES:顯示鏈接器指示
/DISASM:顯示反匯編
/EXPORTS:顯示導出函數表
/HEADERS:顯示文件頭
/IMPORTS:顯示導入函數表
/LINENUMBERS:顯示行號信息
/SECTION:name:顯示某個段
/SECTION:顯示文件概要信息
/SYMBOLS:顯示文件符號表
/TLS:顯示線程局部存儲TLS信息

Ⅳ Attribute和Property的區別

property是指類向外提供的數據區域。
而attribute則是描述對象在編譯時或運行時屬性的,分為固有型和用戶自定義型,其中用戶自定義型可以利用Reflection在運行期獲取。
這兩者是有本質區別的。
資料上說二者一個是service的屬性,而另一個是interface的。
第一種好象更准確,摘要如下:
在很多人的腦海中,Attribute就是類的屬性,Property呢?好像也是類的屬性?因此有很多人不加區別的統一稱為類的屬性,尤其是在寫中文文章的時候。這種心理是典型的鴕鳥心態,眼不見為凈。其實稍微用腳想一下就知道,事實肯定不是這樣的,UML中既然發明了這兩個術語,顯然不是用來冗餘的。它們之間肯定有著千絲萬縷的聯系與區別。
各種各樣的面向對象語言、各種組件技術、模板技術、Web Service技術,其中大部分涉及到了「屬性」這個概念,而其英文術語則常常是Attribute、Property或者Field。很多人一概稱之為「屬性」,有的地方確實可以不加區分,但有的地方卻是差之毫釐、謬以千里。我對於這些紛紛擾擾的技術和術語也很苦惱,但是我們至少可以通過UML中的這兩個術語的解釋找到一個可以參考的標准。無論如何,UML是面向對象技術的集大成者和事實上的標准。
很客觀的說,UML1.4中對於這兩個術語並沒有很清晰的定義,但是其區別還是顯而易見的。Attribute應該是UML1.4中的寵兒,而Property連一個單獨的術語都沒有撈到。誰也沒想到在UML2.0中風雲突變,Attribute從類圖中消失了,而Property堂而皇之入主中原。
1。4中 Attribute是與Classifier相關聯的術語,它比Property的影響范圍要小。Class是Classifier的子類,因此Attribute也可以表示Class的屬性。從上面的定義還可以看出,Attribute可以是Classifier的實例的命名的槽。對於Class來說,其實例就是Object,Object的槽就是對象的屬性值槽。因此,Attribute是可以作為對象的屬性的。而Property似乎沒有這一層的含義。按MOF(元對象設施,OMG的另一個規范,後面會有詳細解釋)的模型層次劃分,Attribute涉及的模型層從M2到M0,而Property似乎只是M2層的概念。
2。0中 Attribute這里僅僅指一個類元的結構特徵,可以將類元的實例聯繫到一個或者一組具體值。而沒有提到實例的槽(slot)等等。我猜想,這是因為UML2.0中已經把Attribute作為Property的一個子集了,所以關於實例的槽(slot)等等的具體賦值方法,都歸結到Property的定義中解釋了。
另外一點值得注意的是,Attribute的定義來自於術語表,而沒有在元模型圖中出現。而Property出現在元模型圖中,並且都做了詳細而具體的解釋。這一點可以看出,UML強化Property,弱化Attribute的決心。
Attribute和Property的總結
這一節對Attribute和Property作一個小結,基於目前最新的UML2.0規范:
l 總體上來說,Attribute是Property的子集,Property會在適當的時機表現為Attribute;
l Property出現在類圖的元模型中,代表了Class的所有結構化特徵;Attribute沒有出現在元模型中,它僅僅在Class的概念中存在,沒有相應的語法了;
l Property有詳細的定義和約束,而Attribute沒有詳細的定義,因此也不能用OCL寫出其約束。
l Property和Attribute都是M2層的概念。在M1層,它們的實例是具體類的屬性;在M0層,它們的實例的實例是具體對象的槽中存儲的值。

對於property和attribute這兩個名詞都叫「屬性」的問題,來源於國內it書籍翻譯界的疏忽。
其實它們來源於兩個不同的領域,attribute屬於OOA/OOD的概念,而property屬於編程語言中的概念。下面我們來說明它們的異同。
Attribute
Attributes是Microsoft .NET Framework文件的元數據,可以用來向運行時描述你的代碼,或者在程序運行的時候影響應用程序的行為。
Property
屬性是面向對象編程的基本概念,提供了對私有欄位的訪問封裝,在C#中以get和set訪問器方法實現對可讀可寫屬性的操作,提供了安全和靈活的數據訪問封裝。關於屬性的概念,不是本文的重點,而且相信大部分的技術人員應該對屬性有清晰的概念。以下是簡單的屬性
區別
可以說兩者沒有可比性,只不過我們國家的語言特點才引起的歧異,其實只要記住Attribute是派生於System,Attribute類之下,它的主要作用是描述,比如某為了描述某個方法是來自與外部的dll,
可以寫如下代碼,這就是一個Attribute,他是一個描述(或者說聲明)
[DllImport("User32.dll")]
Attribute也有很多系統的「默認」屬性,見下表

預定義的屬性

有效目標

說明

AttributeUsage

Class

指定另一個屬性類的有效使用方式

CLSCompliant

全部

指出程序元素是否與CLS兼容

Conditional

Method

指出如果沒有定義相關聯的字元串,編譯器就可以忽略對這個方法的任何調用

DllImport

Method

指定包含外部方法的實現的DLL位置

STAThread

Method(Main)

指出程序的默認線程模型為STA

MTAThread

Method(Main)

指出程序的默認模型為多線程(MTA)

Obsolete

除了Assembly、Mole、Parameter和Return

將一個元素標示為不可用,通知用戶此元素將被從未來的產品

ParamArray

Parameter

允許單個參數被隱式地當作params(數組)參數對待

Serializable

Class、Struct、enum、delegate

指定這種類型的所有公共和私有欄位可以被串列化

NonSerialized

Field

應用於被標示為可串列化的類的欄位,指出這些欄位將不可被串列化

StructLayout

Class、struct

指定類或結構的數據布局的性質,比如Auto、Explicit或sequential

ThreadStatic

Field(靜態)

實現線程局部存儲(TLS)。不能跨多個線程共享給定的靜態欄位,每個線程擁有這個靜態欄位的副本

而Property是指編程過程中的欄位,也即類的成員。
如:
private int hour; //定義私有變數表示"小時",外部是訪問不到的.}
public int Hour// 定義Hour程序介面
{
set { hour=value; }
get { return hour;}

Ⅳ 雙核/四線程是什麼意思,跟四核處理器有什麼不一樣嗎

雙核/四線程指的是採用超線程即是可在同一時間里,應用程序可以使用晶元的不同部分。雖然單線程晶元每秒鍾能夠處理成千上萬條指令,但是在任一時刻只能夠對一條指令進行操作。而超線程技術可以使晶元同時進行多線程處理,使晶元性能得到提升。

雙核四線程實際上是兩個物理核心處理器,是CPU工作時利用超線程技術可以把CPU的一個物理核心模擬出兩個處理線程,讓操作系統誤認為有兩個「物理核心」,俗稱「假四核」,而四核處理器是真正的四顆物理核心處理器。


(5)線程局部存儲tls擴展閱讀

多核心處理器的創新意義:

1、x86多核處理器標志著計算技術的一次重大飛躍。這一重要進步發生之際,正是企業和消費者面對飛速增長的數字資料和互聯網的全球化趨勢,開始要求處理器提供更多便利和優勢之時。

2、多核處理器,較之當前的單核處理器,能帶來更多的性能和生產力優勢,因而最終將成為一種廣泛普及的計算模式。

3、多核處理器還將在推動PC安全性和虛擬技術方面起到關鍵作用,虛擬技術的發展能夠提供更好的保護、更高的資源使用率和更可觀的商業計算市場價值。普通消費者也將比以往擁有更多的途徑獲得更高性能,從而提高他們家用PC和數字媒體計算系統的使用。

Ⅵ 線程特有數據(Thread Specific Data)

在單線程程序中,我們經常要使用 全局變數 來實現多個函數間共享數據。在多線程環境下,由於數據空間是共享的,因此全局變數也為所有線程所共有。但有時在應用程序設計中有必要提供 線程私有 的全局變數,僅在某個線程中有效,但可以跨多個函數訪問,這樣每個線程訪問它自己獨立的數據空間,而不用擔心和其它線程的同步訪問。

這樣在一個線程內部的各個函數都能訪問、但其它線程不能訪問的變數,我們就需要使用 線程局部靜態變數 (Static memory local to a thread) 同時也可稱之為 線程特有數據 (Thread-Specific Data 或 TSD),或者 線程局部存儲 (Thread-Local Storage 或 TLS)。

POSIX 線程庫提供了如下 API 來管理線程特有數據(TSD):

第一參數 key 指向 pthread_key_t 的對象的指針。請 注意 這里 pthread_key_t 的對象佔用的空間是用戶事先分配好的, pthread_key_create 不會動態生成 pthread_key_t 對象。
第二參數 desctructor ,如果這個參數不為空,那麼當每個線程結束時,系統將調用這個函數來釋放綁定在這個鍵上的內存塊。

有時我們在線程里初始化時,需要避免重復初始化。我們希望一個線程里只調用 pthread_key_create 一次,這時就要使用 pthread_once 與它配合。

第一個參數 once_control 指向一個 pthread_once_t 對象,這個對象必須是常量 PTHREAD_ONCE_INIT ,否則 pthread_once 函數會出現不可預料的結果。
第二個參數 init_routine ,是調用的初始化函數,不能有參數,不能有返回值。
如果成功則返回0,失敗返回非0值。

創建完鍵後,必須將其與線程數據關聯起來。關聯後也可以獲得某一鍵對應的線程數據。關聯鍵和數據使用的函數為:

第一參數 key 指向鍵。
第二參數 value 是欲關聯的數據。
函數成功則返回0,失敗返回非0值。

注意: 用 pthread_setspecific 為一個鍵指定新的線程數據時,並不會主動調用析構函數釋放之前的內存,所以調用線程必須自己釋放原有的線程數據以回收內存。

獲取與某一個鍵關聯的數據使用函數的函數為:

參數 key 指向鍵。
如果有與此鍵對應的數據,則函數返回該數據,否則返回NULL。

刪除一個鍵使用的函數為:

參數 key 為要刪除的鍵。
成功則返回0,失敗返回非0值。

注意: 該函數將鍵設置為可用,以供下一次調用 pthread_key_create() 使用。它並不檢查當前是否有線程正在使用該鍵對應的線程數據,所以它並不會觸發函數 pthread_key_create 中定義的 destructor 函數,也就不會釋放該鍵關聯的線程數據所佔用的內存資源,而且在將 key 設置為可用後,在線程退出時也不會再調用析構函數。所以在將 key 設置為可用之前,必須要確定:

在 Linux 中每個進程有一個全局的數組 __pthread_keys ,數組中存放著 稱為 key 的結構體,定義類似如下:

在 key 結構中 seq 為一個序列號,用來作為使用標志指示這個結構在數組中是否正在使用,初始化時被設為0,即表示 不在使用 。 destructor 用來存放一個析構函數指針。

pthread_create_key 會從數組中找到一個還未使用的 key 元素,將其序列號 seq 加1,並記錄析構函數地址,並將 key 在數組 __pthread_keys 中的 下標 作為返回值返回。那麼如何判斷一個 key 正在使用呢?

如果 key 的序列號 seq 為偶數則表示未分配,分配時將 seq 加1變成奇數,即表示正在使用。這個操作過程採用原子 CAS 來完成,以保證線程安全。在 pthread_key_delete() 時也將序列號 seq 加1,表示可以再被使用,通過序列號機制來保證回收的 key 不會被復用(復用 key 可能會導致線程在退出時可能會調用錯誤的析構函數)。但是一直加1會導致序列號回繞,還是會復用 key ,所以調用 pthread_create_key 獲取可用的 key 時會檢查是否有回繞風險,如果有則創建失敗。

除了進程范圍內的 key 結構數組外,系統還在進程中維護關於每個線程的控制塊 TCB(用於管理寄存器,線程棧等),裡面有一個 pthread_key_data 類型的數組。這個數組中的元素數量和進程中的 key 數組數量相等。 pthread_key_data 的定義類似如下:

根據 pthread_key_create() 返回的可用的 key 在 __pthread_keys 數組中的下標, pthread_setspecific() 在 pthread_key_data 的數組 中定位相同下標的一個元素 pthread_key_data ,並設置其序號 seq 設置為對應的 key 的序列號,數據指針 data 指向設置線程特有數據(TSD)的值。

pthread_getspecific() 用於將 pthread_setspecific() 設置的 data 取出。

線程退出時, pthread_key_data 中的序號 seq 用於判斷該 key 是否仍在使用中(即與在 __pthread_keys 中的同一個下標對應的 key 的序列號 seq 是否相同),若是則將 pthread_key_data 中 data(即 線程特有數據 TSD)作為參數調用析構函數。

由於系統在每個進程中 pthread_key_t 類型的數量是有限的,所有在進程中並不能獲取無限個 pthread_key_t 類型。Linux 中可以通過 PTHREAD_KEY_MAX(定義於 limits.h 文件中)或者系統調用 sysconf(_SC_THREAD_KEYS_MAX) 來確定當前系統最多支持多少個 key 。 Linux 中默認是 1024 個 key,這對大多數程序來書已經夠了。如果一個線程中有多個線程局部存儲變數(TLS),通常可以將這些變數封裝到一個數據結構中,然後使用封裝後的數據結構和一個線程局部變數相關聯,這樣就能減少對鍵值的使用。

https://blog.csdn.net/hustraiet/article/details/9857919
https://blog.csdn.net/hustraiet/article/details/9857919
https://blog.csdn.net/caigen1988/article/details/7901248
http://www.bitools.com/?p=2443
https://spockwangs.github.io/blog/2017/12/01/thread-local-storage/
https://www.jianshu.com/p/71c2f80d7bd1
https://blog.csdn.net/cywosp/article/details/26469435
http://www.embeddedlinux.org.cn/emblinuxappdev/117.htm

熱點內容
一台存儲可以配幾個擴展櫃 發布:2025-02-08 01:53:22 瀏覽:564
分布式存儲技術優缺點 發布:2025-02-08 01:51:37 瀏覽:245
linuxsuse重啟 發布:2025-02-08 01:49:27 瀏覽:411
java對稱加密 發布:2025-02-08 01:48:04 瀏覽:523
java報表框架 發布:2025-02-08 01:47:59 瀏覽:930
方舟手游怎麼防止踢出伺服器 發布:2025-02-08 01:42:44 瀏覽:690
c語言中函數的聲明函數 發布:2025-02-08 01:41:08 瀏覽:70
編譯termux 發布:2025-02-08 01:39:42 瀏覽:650
王者榮耀安卓哪裡看ios國服榜 發布:2025-02-08 01:25:54 瀏覽:630
解壓帶教程 發布:2025-02-08 01:16:33 瀏覽:760