I would like to reiterate the problem of the main Python thread that Python is one of the best choices for programming learners who have never learned programming or are not computer professional, the following article will introduce you.
PyThread_acquire_lock can be distinguished by the function parameter waitflag. This waitflag indicates that GIL is unavailable currently. Whether to wait, or more directly, whether the current thread suspends itself through WaitForSingleObject until other threads release GIL, and then the operating system wakes itself up.
If waitflag is 0, Python checks whether the current GIL is available. The owned in GIL indicates whether GIL is available. In the InitializeNonRecursiveMutex above, we can see that this value is initialized to-1. Python checks whether the value is-1. If yes, it means that GIL is available and must be set to 0. When owned is 0, it indicates that the GIL has been occupied by a thread, no longer available.
For the main thread that calls PyEval_InitThread analyzed here, because PyThread _ acquire_lock is called after GIL initialization, no second thread is created at this time, therefore, the main thread can easily obtain the right to use GIL.
Note that the owned check and update operations are completed through a Win32 system API called Interlocked-CompareExchange. This API is an atomic operation. Its function prototype and functions are as follows. Prototype: InterlockedCompareExchange (PLONG dest, long exchange, long compared) function: If * dest = compared, * dest = exchange
Like InterlockedCompareExchange, InterlockedIncrement is also an atomic operation. Its function is to increase the value of mutex-> owned by 1. From this we can see that when a thread starts to wait for GIL, its owned will be increased by 1. Obviously, we can guess that when a thread finally releases GIL.
The GIL owned will be reduced by 1, so that when all the threads that require GIL are finally released, the owned will change to-1 again, meaning that GIL becomes available again. To clearly display this point, let's take a look at the inverse operation of PyThread_aquire_lock, pyThread_release_lock every thread that changes from running to waiting state will call it before being suspended to release the possession of GIL.
In the end, when a thread releases GIL, it will notify all the threads waiting for the hevent of GIL through SetEvent, combined with the previous analysis. If a thread is waiting for the hevent of GIL at this time, it will be awakened by the operating system. This is the mechanism that we introduced earlier in Python to delegate the second difficulty of thread scheduling to the operating system.
At this time, the thread that calls PyEval_InitThread, that is, the main Python thread, has successfully obtained GIL, and finally calls PyThread_get_thread_ident (). Use the Win32 API: GetCurrent-ThreadId to obtain the id of the current main Python thread and assign it to main_thread. main_thread is a static global variable that stores the thread id of the main Python thread, used to determine whether a thread is a main Python thread.
It is worth noting that obj. done is a Semaphore kernel object under Win32. We will immediately see the usage of this special kernel object. We need func and arg to create a thread. However, the API for creating a thread in Win32 only allows users to specify a custom parameter. This is why obj is needed for packaging.
After packaging, call the API _ beginthread for thread creation under Win32 to complete thread creation. The strange thing is that we expect the thread process to be the threadPoc defined in thread1.py, while the thread process specified here is a quite generate bootstrap. In fact, in bootstrap, threadProc defined in thread1.py is finally called.
Now let's clarify the current status of Python. The pythonmain thread is first formed by two win32's primary threads, one is the main thread created by the operating system when the pythonprogram python.exe is executed, and the other is the subthread created through thread1.py.
The main thread obtains GIL while executing PyEval_InitThread, but it has been suspended to wait for the obj. done controlled in the Child thread. The thread process of the sub-thread is bootstrap, but we have already guessed it.
Starting from bootstrap, theadProc defined in python1.py will be executed in the Python interpreter. However, we know that the sub-thread must first obtain GIL to access the Python interpreter. This is a game rule in the Python world, and no exception can be given to anyone. Therefore, to avoid deadlocks, The subthread must notify obj. done before applying for GIL.
- Introduction to Python system files
- How to correctly use Python Functions
- Detailed introduction and analysis of Python build tools
- Advantages of Python in PythonAndroid
- How to Use the Python module to parse the configuration file?