Contenu connexe
Similaire à PHPでマルチスレッド (20)
PHPでマルチスレッド
- 12. ZTS - Zend Thread SafeZTS - Zend Thread Safe
PHPをThread Safeで実行できるようにすることPHPをThread Safeで実行できるようにすること
12
- 13. ZTS - Zend Thread SafeZTS - Zend Thread Safe
configureで指定する必要がある
--enable-maintainer-zts
13
- 14. ZTS - Zend Thread SafeZTS - Zend Thread Safe
Thread Safe版
ZTSの表記が出力される
~ $ php --version
PHP 7.3.14 (cli) (built: Jan 26 2020 22:28:54) ( ZTS DEBUG )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.14, Copyright (c) 1998-2018 Zend Technologies
14
- 15. NTS - Zend Non Thread SafeNTS - Zend Non Thread Safe
Non Thread Safe版
NTSの表記が出力される
~ $ php --version
PHP 7.3.14 (cli) (built: Jan 26 2020 07:47:07) ( NTS DEBUG )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.14, Copyright (c) 1998-2018 Zend Technologies
15
- 22. 続コード続コード
親スレッドが子スレッドを生成するmainコード
// ...
try {
$r1 = new Runtime();
$args = array();
$args[0] = "Zero";
$args[1] = "One";
$r1->run($thread_function, $args);
echo "nEnd of main.n";
} catch (Error $err) {
echo "nError:", $err->getMessage();
} catch (Exception $e) {
echo "nException:", $e->getMessage();
}
22
- 24. pthread - POSIX Threadpthread - POSIX Thread
Parallelが内部的に利用している、マルチスレッドライブラリ
PHPのコードに合わせて追っかけてみる
24
- 25. スレッドの生成 – 親スレッドスレッドの生成 – 親スレッド
Runtimeオブジェクトのインスタンス化と同時に子スレッドが生成さ
れ、そのときruntime変数を親スレッドと子スレッドで共有します
子スレッドはphp_parallel_threadから処理を開始
$r1 = new Runtime();
PHP_METHOD(Runtime, __construct)
...
if (pthread_create(&runtime->thread, NULL, php_parallel_thread, runtime)
!= SUCCESS) {
25
- 29. php_parallel_monitor_wait関数 – 親スレッドphp_parallel_monitor_wait関数 – 親スレッド
runtimeオブジェクトに格納されているstatusをチェックするため
mutexロックを取得
if (pthread_mutex_lock(&monitor->mutex) != SUCCESS) { // mutex取得
return FAILURE;
}
while (!(changed = (monitor->state & state))) {
// PHP_PARALLEL_READY|PHP_PARALLEL_FAILURE 以外の場合(子スレッド初期化中)
if ((rc = pthread_cond_wait(
&monitor->condition, &monitor->mutex)) != SUCCESS) {
pthread_mutex_unlock(&monitor->mutex);
return FAILURE;
}
} // 正常に子スレッドが生成されたら、stateを初期化クリア状態セットし
// mutexのロック解除しPHPの内部へ戻る
29
- 32. php_parallel_thread – 子スレッドphp_parallel_thread – 子スレッド
statusをPHP_PARALLEL_READY|PHP_PARALLEL_RUNNINGへアトミッ
クに変更
親が初期化待ちでwaitしている場合、pthread_cond_signalで親スレ
ッドを起こします
void php_parallel_monitor_set(php_parallel_monitor_t *monitor, int32_t state)
{
// state = PHP_PARALLEL_READY|PHP_PARALLEL_RUNNING
pthread_mutex_lock(&monitor->mutex);
monitor->state |= state;
pthread_cond_signal(
&monitor->condition);
pthread_mutex_unlock(&monitor->mutex);
}
32
- 34. php_parallel_thread – 子スレッドphp_parallel_thread – 子スレッド
処理すべきタスクをruntime->scheduleのzend_llistというリンクリスト
から取得します
タスクはel構造体に詰められ、取得できた場合、リンクリストから除去
されます
php_parallel_schedule_el_t el;
while (!php_parallel_scheduler_pop(runtime, &el)) {
34
- 36. php_parallel_thread – 子スレッドphp_parallel_thread – 子スレッド
タスクがない場合、statusからPHP_PARALLEL_RUNNINGを外した後
PHP_PARALLEL_EXEC | PHP_PARALLEL_CLOSE |
PHP_PARALLEL_KILLED以外の場合、スレッドは停止
while (!(changed = (monitor->state & state))) {
if ((rc = pthread_cond_wait(
&monitor->condition, &monitor->mutex)) != SUCCESS) {
return FAILURE;
}
}
36
- 37. php_parallel_thread – 子スレッドphp_parallel_thread – 子スレッド
タスクがとれた場合、statusをPHP_PARALLEL_RUNNINGに更新し、タ
スクを実行します
frameに格納されている、PHPで設定されたthread関数(Closure)を実
行します
php_parallel_scheduler_run(runtime, el.frame);
static void php_parallel_scheduler_run(php_parallel_runtime_t *runtime,
zend_execute_data *frame) {
...
zend_execute_ex(frame);
37
- 38. タスクの追加 – 親スレッドタスクの追加 – 親スレッド
子スレッドが処理すべきタスクの追加をrun関数でおこないます
$args = array();
$args[0] = "Zero";
$args[1] = "One";
$r1->run($thread_function, $args);
38
- 39. タスクの追加 – 親スレッドタスクの追加 – 親スレッド
closureオブジェクト、thread関数の引数、戻り値を引数にタスクの追
加を実行します
PHP_METHOD(Runtime, run)
{
...
php_parallel_scheduler_push(runtime, closure, argv, return_value);
...
39
- 40. php_parallel_scheduler_add – 親スレッドphp_parallel_scheduler_add – 親スレッド
引数や関数のチェックを行った後に、zend_llistへタスクを追加します
static zend_always_inline void php_parallel_scheduler_add(
php_parallel_runtime_t *runtime,
const zend_function *function,
zval *argv,
php_parallel_future_t *future) {
php_parallel_schedule_el_t el;
...
zend_llist_add_element(&runtime->schedule, &el);
...
40
- 42. php_parallel_monitor_set – 親スレッドphp_parallel_monitor_set – 親スレッド
逆に子スレッドが寝ている場合、conditon変数に対してsignalを送り
寝ている子スレッドを起こします
正常にタスクを追加完了した場合、親スレッドはPHPの内部へ戻りま
す
void php_parallel_monitor_set(php_parallel_monitor_t *monitor, int32_t state)
{
pthread_mutex_lock(&monitor->mutex);
monitor->state |= state;
pthread_cond_signal(
&monitor->condition);
pthread_mutex_unlock(&monitor->mutex);
}
42