史歡歡 周光森 姚永哲
沈陽中鈔信達金融設(shè)備有限公司
1)在線程創(chuàng)建之前,需要初始化線程,設(shè)置線程的優(yōu)先級、是否繼承父進程優(yōu)先級、調(diào)度策略,并分配各個線程的優(yōu)先級。創(chuàng)建線程的函數(shù)是pthread_create()。
2)線程的終止的兩種方式:第一通過return從線程函數(shù)返回,第二種通過調(diào)用pthread_exit()函數(shù)使線程退出。此外,主線程中如果從main函數(shù)返回或是調(diào)用了exit函數(shù)退出主線程,則整個進程終止,此時所有的其他線程也將終止。另一種是,如果主線程調(diào)用pthread_exit函數(shù),則僅僅是主線程消亡,進程不會結(jié)束,其他線程也不會結(jié)束,直到所有的線程都結(jié)束時,進程才結(jié)束。
線程與線程之間通訊,互相交互變量,不能總用全局變量,這樣會出現(xiàn)A線程正在改全局變量的值,B線程卻在讀全局變量的值,因為各線程是并行工作,所以需要加互斥鎖、條件變量或消息隊列來同步。
1)互斥鎖pthread_mutex_lock(unlock或trylock):用來防止兩個進程或線程在同一時刻訪問相同的共享資源。如果互斥量已經(jīng)上鎖,調(diào)用線程會阻塞,直到互斥量被解鎖。比如A和B兩個線程都要用a變量,在A線程中,加鎖之后改變a變量的值,然后解鎖,而在B線程中,加鎖之后讀a變量的值,然后解鎖,加鎖和解鎖必須判斷是否成功,否則對a變量的讀寫會出錯,最好用pthread_mutex_trylock加鎖,如果加鎖失敗,會返回EBUSY,成功則返回0,返回EBUSY說明另一線程對這個變量加鎖后還未解鎖。此外,阻塞和非阻塞的意思是,阻塞是一直加鎖直到成功,非阻塞是加鎖完畢后不管成功與否都返回。
2)條件變量cond
條件變量的基本操作是當(dāng)觸發(fā)條件(當(dāng)條件變?yōu)檎鏁r),等待條件,掛起線程直到其他線程觸發(fā)條件。即A線程先進入wait等待,讓其掛起,等待B線程執(zhí)行激活后,A線程繼續(xù)執(zhí)行。為了防止競爭,條件變量總是和一個互斥鎖結(jié)合在一起。pthread_cond_wait一般嵌套在while(條件)中,條件第一次滿足就可以。激活等待線程是激發(fā)條件有兩種形式,pthread_cond_signal( )激活一個等待該條件的線程,存在多個等待線程時按入隊順序激活其中一個;而pthread_cond_broadcast()則激活所有等待線程。
3)消息隊列:在A線程中改變某個變量后,發(fā)消息給B線程,B線程在沒有得到消息時處于掛起狀態(tài),除非A線程給B線程發(fā)消息,B線程接收到消息才開始執(zhí)行msgrcv的下一行代碼。msgsnd向隊列末端添加一條新消息;msgrcv從隊列中取消息,取消息是不一定遵循先進先出的,也可以按消息的類型字段取消息;
4)線程之間是異步的,無法確定哪個線程先執(zhí)行。如果在同一優(yōu)先級中有N個線程,需要使用sleep來調(diào)整各個線程執(zhí)行的順序。
5)Linux下多個線程同時對一個文件進行寫操作,需要使用文件鎖解決沖突,使用int flock(int fd,int operation)(鎖定文件或解除鎖定)函數(shù)。flock()會依參數(shù)operation所指定的方式對參數(shù)fd所指的文件做各種鎖定或解除鎖定的動作。此函數(shù)只能鎖定整個文件,無法鎖定文件的某一區(qū)域。LOCK_EX 建立互斥鎖定,一個文件同時只有一個互斥鎖定。LOCK_NB 無法建立鎖定時,此操作可不被阻斷,馬上返回進程。通常與LOCK_EX 做OR(|)組合。
if(flock(fileno(文件指針),LOCK_EX | LOCK_NB)== FAILURE)//文件加鎖
if(flock(fileno(文件指針),LOCK_UN)== FAILURE)//釋放文件鎖
1)線程中程序不運行的三種狀態(tài)睡眠sleep()、阻塞、掛起,他們的區(qū)別是:
①掛起:沒有滿足的運行條件,正在待命,比如msgrcv,沒有接收到消息時就掛起,讓別的線程執(zhí)行,自己等待msgsnd,一旦接收到消息,繼續(xù)執(zhí)行;
②sleep( ):歇一會,讓別的線程先運行;
③阻塞:線程由于等待處理器外的其他條件無法運行,如條件變量的改變、加鎖互斥量或I/O操作結(jié)束。
2)單線程進入死循環(huán)
如果線程中所有程序的執(zhí)行需要滿足if條件,但if條件一直不滿足,這個線程將處于死循環(huán),使別的線程也無法執(zhí)行。可以在if之后加入else,里面是sleep(),在執(zhí)行sleep()期間,別的線程就可以運行。
3)線程定時執(zhí)行
如果想讓在線程定時執(zhí)行某個函數(shù),需要用到setitimer()有兩個功能,一是指定一段時間后,才執(zhí)行某個function,二是每間隔一段時間就執(zhí)行某個function。如果要實現(xiàn)間隔執(zhí)行,程序中一定要加pause( )函數(shù),并且嵌套在while(1)中。
在應(yīng)用軟件中編寫各個線程的程序。調(diào)用linux中的系統(tǒng)函數(shù)一定要接收返回值來判斷是否執(zhí)行成功。linux程序不能實時仿真,調(diào)試程序只能通過printf打印變量值到串口。所以在寫linux程序,一定要防止內(nèi)存泄漏,比如數(shù)組、變量類型、指針一定要推敲使用。遇到內(nèi)存泄漏,用printf來打印定位。