The establishment of a multi-threaded Python environment is straightforward, mainly the creation of GIL. We already know the significance of GIL for the multi-threaded mechanism of Python. But how is GIL implemented? Well, this is still a very troublesome problem.
-
- 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 */
-
- }
I finally saw the mysterious GILinterpreter_lock). I never expected it, but it actually showed a simple void *. But in another thought, in C, void * can be almost anything. This guy is a omnipotent container.
As you can see, no matter how many threads are created, the action of creating a multi-threaded environment in Python is only executed once. At the beginning of PyEval_InitThreads, Python checks whether GIL has been created. If yes, no action is performed. Otherwise, the GIL is created. The creation of GIL is completed by PyThread_allocate_lock. Let's take a look at what the GIL is.
Here, we finally see the platform relevance of the Python multithreading mechanism. Under the Python25 \ Python directory, there are a large number of files such as thread. In these files, native threads of different operating systems are encapsulated and exposed to Python through a unified interface. For example, PyThread_allocate_lock here is such an interface.
- How to Implement Python Technology in games
- Deep introduction to Python Interfaces
- Description of Python Extension
- Elaborate on Python PyString Object
- How to perform Python string operations?
The thread_nt.h here is packaged with the native thread of the Win32 platform. In the code analysis later in this chapter, there will be a lot of platform-related code. We take the Win32 platform as an example. In PyThread_allocate_lock, similar to PyEval_InitThreads, it checks an initialized variable. If GIL indicates whether the Python multi-thread environment has been established.
The initialized variable indicates whether the initialization is complete to use the native thread provided by the underlying platform. These initialization actions are usually provided by the underlying operating system. Different Operating Systems may need different initialization actions.
In PyThread_allocate_lock, a key struct PNRMUTEX is displayed. We find that this struct is the return value of the function, which is actually the interperter_lockGIL to be created in PyEval_InitThread ). It turns out GIL is this guy. Let's take a look at it.
- [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 */
-
- }
In NRMUTEX, the types of all data members are the type styles on the Win32 platform. Both owned and thread_id are common, while HANDLE hevent is worth noting, let's take a look at what AllocNon-RecursiveMutex has prepared for this hevent.