В этом введении к pthreads я читал, что:
Когда программист вызывает Thread :: start, создается новый поток, контекст интерпретатора PHP инициализируется, а затем (безопасно) обрабатывается, чтобы отразить контекст, который сделал вызов :: start.
И позже в тексте рассматривается проблема с ошибкой сегментации. Приведен пример ошибки сегментации:
class W extends Worker {
public function run(){}
}
class S extends Stackable {
public function run(){}
}
/* 1 */
$w = new W();
/* 2 */
$j = array(
new S(), new S(), new S()
);
/* 3 */
foreach ($j as $job)
$w->stack($job);
/* 4 */
$j = array();
$w->start();
$w->shutdown();
Вышеприведенный пример всегда будет segfault; шаги 1-3 являются совершенно нормальными, но перед тем, как рабочий будет запущен, удаленные сложенные объекты будут удалены, что приведет к segfault, когда Работу разрешено запустить.
Вопросы:
start()
, или только в то время, когда интерпретатор видит ссылку на переменную старого контекста? Другими словами, достаточно ли содержать refcounts> 0 до вызова функции start()
?Stackable
в объекте Worker
чтобы их пересчет после перезаписывания $j
был еще 1, и segfault не мог произойти?1) Весь контекст копируется при запуске потока. Вы должны поддерживать refcounts> 0, пока штабелированные объекты не будут выполняться рабочим потоком.
2) Счетчик ссылок, встроенный в переменные в PHP, никогда не был подготовлен для многопоточности, многие функции api уменьшались и увеличивались, и нет возможности синхронизации (блокировки). По этой причине вы несете ответственность за поддержание ссылки на любой объект, который предназначен для выполнения другим потоком.
Эти довольно неприятные, но неизбежные факты могут быть побочными, используя абстракцию Pool
снабженную pthreads. Он правильно поддерживает ссылки для вас.