threading.py 中 Lock 的定义如下:
x
try:
import thread
except ImportError:
...
raise
...
_allocate_lock = thread.allocate_lock
...
Lock = _allocate_lock
...
接下来,进入到 Python 的源代码,查看 thread 模块的源码(Modules/threadmodule.c):
x
static lockobject *newlockobject(void);
static PyObject *
thread_PyThread_allocate_lock(PyObject *self)
{
return (PyObject *) newlockobject();
}
static lockobject *
newlockobject(void)
{
lockobject *self;
self = PyObject_New(lockobject, &Locktype);
if (self == NULL)
return NULL;
self->lock_lock = PyThread_allocate_lock();
self->in_weakreflist = NULL;
if (self->lock_lock == NULL) {
Py_DECREF(self);
PyErr_SetString(ThreadError, "can't allocate lock");
return NULL;
}
return self;
}
static PyMethodDef thread_methods[] = {
...
{"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock,
METH_NOARGS, allocate_doc},
...
}
PyMODINIT_FUNC
initthread(void)
{
...
/* Create the module and add the functions */
m = Py_InitModule3("thread", thread_methods, thread_doc);
...
}
可见创建锁用的是 PyThread_allocate_lock(),该函数是 Python/thread.c 提供的,而 Python/thread.c 只是一个入口文件,不同操作系统的线程实现被放到了不同的文件中,比如操作系统 foobar 的实现在 Python/thread_foobar.h 文件中,Python/thread.c 根据配置决定包含哪个文件。接下来分析 POSIX 系统的实现(Python/thread_pthread.h):
x
// 如果系统支持信号量,那么直接使用信号量,否则使用互斥变量和条件变量模拟信号量。
// 之所以不直接用 pthread mutex 作为 Python 锁类型的实现,是因为 mutex 不支持:
// 1,线程尝试锁定它已经锁定的 mutex
// 2,线程尝试解锁其它线程锁定的 mutex
PyThread_type_lock
PyThread_allocate_lock(void)
{
sem_t *lock;
int status, error = 0;
dprintf(("PyThread_allocate_lock called\n"));
if (!initialized)
PyThread_init_thread();
lock = (sem_t *)malloc(sizeof(sem_t));
if (lock) {
status = sem_init(lock,0,1);
CHECK_STATUS("sem_init");
if (error) {
free((void *)lock);
lock = NULL;
}
}
dprintf(("PyThread_allocate_lock() -> %p\n", lock));
return (PyThread_type_lock)lock;
}
Python 中使用的是匿名信号量,下面将简单介绍 POSIX 的匿名信号量。
信号量是一种用于在不同进程间或同一进程内的不同线程间进行同步的工具。
POSIX 提供两类信号量:有名(named)信号量和基于内存的(memory-based)信号量,后者也被称为无名(unnamed)信号量。
POSIX 信号量有三种操作:
POSIX 信号量的函数接口如下图所示:
sem_trywait() 和 sem_wait() 的差别是:当信号量的值等于0时,该函数直接 EAGAIN 错误,调用线程不会被阻塞。