浅析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. }  

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

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

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

  • 游戏中如何进行Python技术
  • 深度Python接口介绍
  • 扩展Python的相关说明
  • 阐述Python PyString Object对象
  • 如何进行Python字符串操作?

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

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

在PyThread_allocate_lock中,出现了一个关键的结构体PNRMUTEX,我们发现,这个结构体是函数的返回值,实际上也就是PyEval_InitThread中需要创建的那个interperter_lockGIL)。原来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准备了什么。

评论关闭