如何進(jìn)行Python主線程設(shè)置
下面給大家一個(gè)寶貴的建議,對(duì)于那些從來沒有學(xué)習(xí)過編程或者并非計(jì)算機(jī)專業(yè)的編程學(xué)習(xí)者而言,Python主線程是最好的選擇之一,并建議那些初學(xué)的程序員先從Python開始學(xué)習(xí)編程。
如果waitflag為0,Python會(huì)檢查當(dāng)前GIL是否可用,GIL中的owned是指示GIL是否可用的變量,在前面的InitializeNonRecursiveMutex中我們看到這個(gè)值被初始化為-1,Python會(huì)檢查這個(gè)值是否為-1,如果是,則意味著GIL可用。
必須將其置為0,當(dāng)owned為0后,表示該GIL已經(jīng)被一個(gè)線程占用,不再可用。對(duì)于我們這里分析的調(diào)用PyEval_InitThread的主線程而言,由于在初始化GIL之后就調(diào)用PyThread_ acquire_lock申請(qǐng)GIL。
到這時(shí),并沒有第二個(gè)線程被創(chuàng)建,所以主線程會(huì)輕而易舉地獲得GIL的使用權(quán)。注意這里的檢查和更新owned的操作是通過一個(gè)Win32的系統(tǒng)API——Interlocked- CompareExchange——來完成的。這個(gè)API是一個(gè)原子操作,其函數(shù)原形和功能如下。
與InterlockedCompareExchange相同的,InterlockedIncrement也是一個(gè)原子操作,其功能是將mutex->owned的值增加1。從這里可以看到,當(dāng)一個(gè)線程開始等待GIL時(shí),其owned就會(huì)被增加1。
顯然我們可以猜測(cè),當(dāng)一個(gè)線程最終釋放GIL時(shí),一定會(huì)將GIL的owned減1,這樣當(dāng)所有需要GIL的線程都最終釋放了GIL之后,owned會(huì)再次變?yōu)?1,意味著GIL再次變?yōu)榭捎谩?/P>
為了清晰地展示這一點(diǎn),我們現(xiàn)在就來看看PyThread_aquire_lock的逆運(yùn)算,PyThread_release_lock每一個(gè)將從運(yùn)行轉(zhuǎn)態(tài)轉(zhuǎn)為等待狀態(tài)的線程都會(huì)在被掛起之前調(diào)用它以釋放對(duì)GIL的占有。
- void PyThread_release_lock(PyThread_type_lock aLock)
- {
- LeaveNonRecursiveMutex((PNRMUTEX) aLock);
- }
- BOOL LeaveNonRecursiveMutex(PNRMUTEX mutex)
- {
- /* We don't own the mutex */
- mutex->thread_id = 0 ;
- return
- InterlockedDecrement(&mutex->owned) < 0 ||
- SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on
- them up */
- }
最終,一個(gè)線程在釋放GIL時(shí),會(huì)通過SetEvent通知所有在等待GIL的hevent這個(gè)Event內(nèi)核對(duì)象的線程,結(jié)合前面的分析。如果這時(shí)候有線程在等待GIL的hevent,那么將被操作系統(tǒng)喚醒。這就是我們?cè)谇懊娼榻B的Python主線程將線程調(diào)度的第二個(gè)難題委托給操作系統(tǒng)來實(shí)現(xiàn)的機(jī)制。
到了這時(shí),調(diào)用PyEval_InitThread的線程(也就是Python主線程)已經(jīng)成功獲得了GIL,最后會(huì)調(diào)用PyThread_get_thread_ident(),通過Win32的API:GetCurrent- ThreadId,獲得當(dāng)前Python主線程的id。
【編輯推薦】