Mvo*_*sek 2 php c c++ windows thread-safety
骨架文件中的ZEND_TSRMLS_CACHE_UPDATE指令有什么作用?php/ext
何时以及为何需要它?
当另一个 init. PHP_MINIT_FUNCTION(%EXTNAME%)添加了类似函数,是否也ZEND_TSRMLS_CACHE_UPDATE需要将指令作为该函数中的第一条语句?
第一件事首先,您的问题不清楚,原因有两个:
你必须提到你正在尝试理解 ZTS ie Zend Thread Safe with PHP
您文件编译或了解您的系统要求是什么,即您使用的操作系统以及您使用的线程类型。
第二件事你还没明白MINIT和RINIT的区别首先让我们了解一下两者的区别
您必须了解 C 编程中的全局变量。假设你对PHP的扩展编译有一定的了解。在 PHP 中,全局变量分为两种类型:
True Globals 是传统的 C 全局变量,因为它们在设计上还不错,但在 Threads 并发运行环境中无法受到保护。PHP 允许他们在 PHP 处理请求时进行读取。真正的全局变量可以在线程环境内部或外部更改。让我们看一个例子来进一步解释它:
static int variable; /* true global */
PHP_MINIT(my_ext) /* PHP Module initialization */
{
if (something()) {
variable = 3; /* writing to a true global */
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码解释了每个 PHP 扩展的样子。所谓的 MINIT 钩子是关于 PHP 扩展初始化的。在这一步骤中,PHP 正在启动,然后可以安全地写入或读取全局变量,就像示例中所做的那样。
由于创建线程是为了同时处理多个请求,因此在该线程中保持每个变量值完整是非常重要的,这样值只能由该线程读取或写入。因此,线程请求的初始化是通过 RINIT 完成的。现在同样的例子将是这样的:
PHP_RINIT(my_ext) /* PHP Request initialization */
{
if (something()) {
MYEXT_G(variable) = 3; /* writing to a thread global */
}
}
Run Code Online (Sandbox Code Playgroud)
只有 1 个不同之处,即使用 MYEXT_G 宏,我将在本答案稍后解释。
为了更好地理解事物,您可能还需要了解 TSRM
因为 ZTS 是为使用线程安全资源管理器层而设计的,我们称之为 TSRM 层。这只是一些简单的 C 代码,对于线程而言,仅是一些理解事物所需的解释。它启用了一些低级线程库:
AT TSRM 启动 PHP 调用tsrm_startup()。由于 PHP 启动并没有如何构建安全保护所需的线程或资源。它将为每个创建的线程准备一个检查表。这个启动步骤也很重要,因为我们在这里创建了 TLS 密钥,以及我们需要同步的 TLS 互斥锁。
static pthread_key_t tls_key;
TSRM_API int tsrm_startup(int expected_threads,
int expected_resources, int debug_level, char *debug_filename)
{
pthread_key_create( &tls_key, 0 ); /* Create the key */
....
....
}
#define MUTEX_T pthread_mutex_t *
TSRM_API MUTEX_T tsrm_mutex_alloc(void)
{
MUTEX_T mutexp;
mutexp = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
pthread_mutex_init(mutexp,NULL);
return mutexp;
}
Run Code Online (Sandbox Code Playgroud)
是时候添加新的资源线程了。内存区域有大小,需要一些初始化(构造函数)和去初始化(析构函数)。该内存区域称为 TSRM 资源,将被 TSRM 层赋予一个唯一的资源 ID。调用者应该保存 ID,因为它需要从 TSRM 返回受保护的内存区域来读取或写入变量值。
TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id,
size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
{
....
//For allocation of memory saving constructor and destruction function
// Saving Size of required memory allocated
// Resources ID Returning back
}
Run Code Online (Sandbox Code Playgroud)
在每个新请求的最开始,都会调用 ts_resource_ex() 函数。该函数读取当前线程 id 并尝试获取为该线程分配的资源,也就是专用于当前线程全局变量的内存区域。
现在您对有关 ZEND_TSRMLS_CACHE_UPDATE 的问题的回答。
/* {{{ PHP_RINIT_FUNCTION
*/
PHP_RINIT_FUNCTION(%EXTNAME%)
{
#if defined(ZTS) && defined(COMPILE_DL_%EXTNAMECAPS%)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
return SUCCESS;
}
/* }}} */
Run Code Online (Sandbox Code Playgroud)
这是宏扩展:
#define ZEND_TSRMLS_CACHE_UPDATE() _tsrm_ls_cache = tsrm_get_ls_cache();
Run Code Online (Sandbox Code Playgroud)
对于 pthread 实现:
#define tsrm_get_ls_cache pthread_getspecific(tls_key)
Run Code Online (Sandbox Code Playgroud)
最后,您应该更好地了解现在如何使用宏在扩展中访问全局变量:
#ifdef ZTS
#define MYEXT_G(v) (((MYEXT_globals *) (*((void ***) _tsrm_ls_cache))[((MYEXT_globals_id)-1)])->(v))
Run Code Online (Sandbox Code Playgroud)
使用 MYEXT_G() 宏访问全局变量,当使用线程环境时,它将_tsrm_ls_cache使用此扩展名的 id扩展以探测区域:MYEXT_globals_id。
| 归档时间: |
|
| 查看次数: |
265 次 |
| 最近记录: |