浅析Python多线程问题

开发 后端
一个程序里可能会包含多个执行的线程。在这里,每个线程被分为Python多线程里一个单独的块,每个进程可以含有多个块,可以共享多个块中的数据。

Python多线程环境的建立,说得直白一点,主要就是创建GIL。我们已经知道GIL对于Python的多线程机制的重要意义,然而这个GIL到底是如何实现的呢,哎这还是个非常困扰的问题。 

  1.  
  2. PNRMUTEX AllocNonRecursiveMutex(void)  
  3.  
  4. {  
  5.  
  6.     PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;  
  7.  
  8.     if(mutex && !InitializeNonRecursiveMutex(mutex)) {  
  9.  
  10.             free(mutex);  
  11.  
  12.             Mutex = NULL;  
  13.  
  14.     }  
  15.  
  16.     return mutex ;  
  17.  
  18. }  
  19.  
  20. BOOL InitializeNonRecursiveMutex(PNRMUTEX mutex)  
  21.  
  22. {  
  23.  
  24.     ……  
  25.  
  26.     mutex->owned = -1 ;  /* No threads have entered NonRecursiveMutex */  
  27.  
  28.     mutex->thread_id = 0 ;  
  29.  
  30.     mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;  
  31.  
  32.     return mutex->hevent != NULL ;  /* TRUE if the mutex is created */  
  33.  
  34. }  

终于见识到了神秘的GIL(interpreter_lock),没想到吧,万万没想到,它居然指示一个简单的void*。但是转念一想,在C中void*几乎可以是任何东西,这家伙,可是个***容器啊。

可以看到,无论创建多少个线程,Python建立多线程环境的动作只会执行一次。在PyEval_InitThreads的开始,Python会检查GIL是否已经被创建。如果是,则不再进行任何动作,否则,就会创建这个GIL。创建GIL的工作由PyThread_allocate_lock完成,我们来看一看这个GIL到底是何方神圣。

在这里,我们终于看到了Python多线程机制的平台相关性,在Python25\Python目录下,有一大批thread这样的文件。在这些文件中,包装了不同操作系统的原生线程,并通过统一的接口暴露给Python,比如这里的PyThread_allocate_lock就是这样一个接口。#t#

我们这里的thread_nt.h中包装的是Win32平台的原生thread,在本章中后面的代码剖析中,还会有大量与平台相关的代码,我们都以Win32平台为例。在PyThread_allocate_lock中,与PyEval_InitThreads非常类似的,它会检查一个initialized的变量,如果说GIL指示着Python多线程环境是否已经建立。

那么这个initialized变量就指示着为了使用底层平台所提供的原生thread,必须的初始化动作是否完成。这些必须的初始化动作通常都是底层操作系统所提供的API,不同的操作系统可能需要不同的初始化动作。

在PyThread_allocate_lock中,出现了一个关键的结构体PNRMUTEX,我们发现,这个结构体是函数的返回值,实际上也就是PyEval_InitThread中需要创建的那个interperter_lock(GIL)。原来GIL就是这个家伙,我们来看一看它的真身。

  1. [thread_nt.h]  
  2.  
  3. PNRMUTEX AllocNonRecursiveMutex(void)  
  4.  
  5. {  
  6.  
  7.     PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ;  
  8.  
  9.     if(mutex && !InitializeNonRecursiveMutex(mutex)) {  
  10.  
  11.             free(mutex);  
  12.  
  13.             Mutex = NULL;  
  14.  
  15.     }  
  16.  
  17.     return mutex ;  
  18.  
  19. }  
  20.  
  21. BOOL InitializeNonRecursiveMutex(PNRMUTEX mutex)  
  22.  
  23. {  
  24.  
  25.     ……  
  26.  
  27.     mutex->owned = -1 ;  /* No threads have entered NonRecursiveMutex */  
  28.  
  29.     mutex->thread_id = 0 ;  
  30.  
  31.     mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;  
  32.  
  33.     return mutex->hevent != NULL ;  /* TRUE if the mutex is created */  
  34.  
  35. }  

在NRMUTEX中,所有的数据成员的类型都是Win32平台下的类型风格了,owned和thread_id都很普通,而其中的HANDLE hevent却值得注意,我们来看看AllocNon- RecursiveMutex究竟为这个hevent准备了什么。

责任编辑:chenqingxiang 来源: 博客园
相关推荐

2011-04-08 10:36:38

MFC多线程

2009-07-03 17:18:34

Servlet多线程

2010-03-03 17:44:07

Python多线程

2009-08-12 18:04:44

编写C#多线程

2011-08-29 16:16:22

Lua函数多线程

2009-07-17 17:29:13

多任务多线程

2011-06-24 11:12:39

Qt 多线程 线程

2011-06-24 11:03:31

Qt 多线程 线程

2009-04-27 13:15:04

多线程方法run()

2019-09-26 10:19:27

设计电脑Java

2009-08-21 11:31:59

异步和多线程的区别

2021-03-05 07:38:52

C++线程编程开发技术

2009-07-03 16:53:11

Servlet容器

2010-03-16 19:29:26

Java多线程操作

2013-05-29 10:47:50

Android开发Java多线程java面试题

2023-10-06 23:06:01

多线程Python

2010-01-18 14:09:58

C++多线程

2015-12-22 10:39:52

Java多线程问题

2017-01-19 10:24:38

Java多线程问题

2014-08-13 10:41:08

linux线程
点赞
收藏

51CTO技术栈公众号