如何進(jìn)行建立Python主線程?
在Python里如果你建立一個(gè)程序,就是一個(gè)進(jìn)程,其中包含一個(gè)線程,這個(gè)就是主線程,而是為了提高資源使用效率來(lái)提高系統(tǒng)的效率,希望大家能夠再次學(xué)到自己想要的信息。
從這里可以看到,當(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)在就來(lái)看看PyThread_aquire_lock的逆運(yùn)算,PyThread_release_lock每一個(gè)將從運(yùn)行轉(zhuǎn)態(tài)轉(zhuǎn)為等待狀態(tài)的線程都會(huì)在被掛起之前調(diào)用它以釋放對(duì)GIL的占有。
- [thread_nt.h]
- PNRMUTEX AllocNonRecursiveMutex(void)
- {
- PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;
- if(mutex && !InitializeNonRecursiveMutex(mutex)) {
- free(mutex);
- Mutex = NULL;
- }
- return mutex ;
- }
- BOOL InitializeNonRecursiveMutex(PNRMUTEX mutex)
- {
- ……
- mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */
- mutex->thread_id = 0 ;
- mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;
- return mutex->hevent != NULL ; /* TRUE if the mutex is created */
- }
最終,一個(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)來(lái)實(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,并將其賦給main_thread,main_thread是一個(gè)靜態(tài)全局變量,專職存儲(chǔ)Python主線程的線程id,用以判斷一個(gè)線程是否是Python主線程。
在完成了多線程環(huán)境的初始化之后,Python會(huì)開始創(chuàng)建底層平臺(tái)的原生thread,以thread1.py為例,這個(gè)原生thread將執(zhí)行threadProc所定義的操作。從現(xiàn)在開始,為了描述的清晰性,我們將Python主線程,也就是調(diào)用thread_PyThread_start_new_thread創(chuàng)建新的線程的線程稱為主線程,而將與threadProc對(duì)應(yīng)的原生thread稱之為子線程。現(xiàn)在我們來(lái)看看一個(gè)子線程是如何被創(chuàng)建的。
- static PyObject* thread_PyThread_start_new_thread(PyObject *self, PyObject
- *fargs)
- {
- PyObject *func, *args, *keyw = NULL;
- struct bootstate *boot;
- long ident;
- PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3, &func, &args, &keyw);
- //[1]:創(chuàng)建bootstate結(jié)構(gòu)
- boot = PyMem_NEW(struct bootstate, 1);
- boot->interp = PyThreadState_GET()->interp;
- boot->funcfunc = func;
- boot->argsargs = args;
- boot->keywkeyw = keyw;
- //[2]:初始化多線程環(huán)境
- PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
- //[3]:創(chuàng)建線程
- ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
- return PyInt_FromLong(ident);
- [thread.c]
- /* Support for runtime thread stack size tuning.
- A value of 0 means using the platform's default stack size
- or the size specified by the THREAD_STACK_SIZE macro. */
- static size_t _pythread_stacksize = 0;
- [thread_nt.h]
- long PyThread_start_new_thread(void (*func)(void *), void *arg)
- {
Python主線程通過調(diào)用PyThread_start_new_thread完成創(chuàng)建子線程的工作。為了清晰地理解PyThread_start_new_thread的工作,我們需要特別注意該函數(shù)的參數(shù)。從thread_ PyThread_start_new_thread中可以看到,這里的func實(shí)際上是函數(shù)t_bootstrap,而arg則是在thread_PyThread_start_new_thread中創(chuàng)建的bootstate結(jié)構(gòu)體boot。在boot中,保存著Python程序(thread1.py)中所定義的線程的信息。
【編輯推薦】