Is created by the operating system, and the other is a sub-thread created through thread1.py.
In [1] of code listing 15-1, we noticed that the PyInter-preterState object of the Python virtual machine is saved in boot-> interp, this object carries global information such as the Python module pool. All threads in Python share the global information.
For the initialization action of the multi-threaded environment shown in [2] of code listing 15-1, it is worth noting that the multi-threaded environment is not supported when Python is started. In other words, the data structures and GIL that support multithreading in Python are not created. This is because most Python programs do not require multithreading.
- [Threadmodule. c]
-
- 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]: Create a bootstate Structure
-
- Boot=PyMem_NEW(Struct bootstate, 1 );
-
- Boot->Interp=PyThreadState_GET()->Interp;
-
- Boot->FuncFunc= Func;
-
- Boot->ArgsArgs= Args;
-
- Boot->KeywKeyw= Keyw;
-
- // [2]: Initialize the multi-threaded Environment
-
- PyEval_InitThreads ();/* Start the interpreter's thread-awareness */
-
- // [3]: Create a thread
-
- 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)
-
- {
-
- Unsigned long rv;
-
- Callobj obj;
-
- Obj. id=-1;/* guilty until proved innocent */
-
- Obj. func= Func;
-
- Obj. arg= Arg;
-
- Obj. done=CreateSemaphore(NULL, 0, 1, NULL );
-
- Rv=_ Beginthread(Bootstrap, _ pythread_stacksize, & obj);/* use default stack size */
-
- If (Rv= (Unsigned long)-1 ){
-
- // Raw thread creation failed
-
- Obj. id=-1;
-
- }
-
- Else {
-
- WaitForSingleObject (obj. done, INFINITE );
-
- }
-
- CloseHandle (HANDLE) obj. done );
-
- Return obj. id;
-
- }
If multiple threads appear in a Python script that simply calculates word frequency, we will be crazy about such code. Multi-threaded support is not costly. The simplest point is to activate the multi-threaded mechanism.
The executed Python program does not have multithreading, so after 100 commands, the Python virtual machine will also activate thread scheduling. If multithreading is not activated, the Python virtual machine does not have to do this useless work. Therefore, Python selects a policy that allows users to activate the multithreading mechanism. When a Python virtual machine is started, the multi-thread mechanism is not activated. It only supports a single thread. Once the user calls thread. start_new_thread.
Explicitly instruct the Python Virtual Machine to create a new thread so that Python can realize that users need multi-thread support. At this time, python virtual opportunity Automatically Establishes the data structure, environment, and the crucial GIL required by the multithreading mechanism. Here, we finally see the platform relevance of the multithreading mechanism in Python. Under the Python25 \ Python directory, there is a large thread _***. h. These files encapsulate native threads of different operating systems.
- New version of Python-Python 3.0
- Analysis of first-time Python deployment problems
- Powerful and quick full parsing of Python operating languages
- Rich Python debugger Resources
- A summary of Python interactive skills
And exposed to Python through a unified interface. For example, PyThread_allocate_lock here is such an interface. The thread_nt.h here encapsulates 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 use the Win32 platform as an example. The hevent in GILNRMUTEX is the kernel object of Event on the Win32 platform, and thread_id records the id of the GIL thread at any time.
Here, the truth about the thread mutex mechanism in the Python Virtual Machine gradually emerges. It seems that Python achieves thread mutex through Event under Win32, and friends who are familiar with Win32 may immediately think of it, there must be a WaitForSingleObject corresponding to this Event.
After PyEval_InitThreads successfully creates GIL through PyThread_allocate_lock, the current thread begins to follow the rules of the Python multithreading mechanism: Before calling any Python c api, you must first obtain GIL. Therefore, PyEval_InitThreads tries to obtain GIL through PyThread_acquire_lock.
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, it will definitely subtract 1 from the GIL owned so that after all the threads that need GIL are finally released, owned will change to-1 again, meaning GIL will become 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.
- 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?