Блокировка в PHP для достижения критического элемента - неожиданные результаты с MySQL

StackOverflow https://stackoverflow.com/questions/3558989

Вопрос

Цель состоит в том, чтобы иметь PHP-скрипт с определенным сечением кода, который может выполняться только одним потоком / процессом одновременно.

Некоторые ограничения:

  • Семафоры не доступны в моей системе
  • Руководство упоминает, что Flock () нельзя полагаться на многопоточных серверах, поэтому стадо () отсутствует. (подтвердил это)

Так что думал, что это будет возможно (почему нет?) Использовать MySQL для синхронизации, но я получаю неожиданные результаты.

Чтобы проверить, у меня есть два вкладка браузера открыты с помощью скрипта TEST.PHP

mysql_connect ($ dbhost, $ dbusername, $ dbpassword); mysql_select_db ($ database_name);

$ sql = "Выберите my_val из my_table КУДА my_var= 'status' "; $ RESVEST = mysql_query ($ sql) или die (mysql_Error ()); $ row = mysql_fetch_array ($ Результат, mysql_assoc); recho" Состояние: ". $ row ['my_val']."
n "; mysql_free_result ($ результат);

Если ($ row ['my_val'] == 'Running') умирает (процесс уже работает! ');

// Ввод критического раздела

$ sql = "обновление my_table ЗАДАВАТЬ my_val= «Работает», где my_var= «Состояние» »; mysql_query ($ sql);

сон (10); // делайте некоторую работу здесь. эхо готовая работа
';

// Оставьте критический раздел. Пусть другие знают $ sql = "обновление my_table ЗАДАВАТЬ my_val= 'Not_running' где my_var= «Состояние» »; mysql_query ($ sql);

Стол:

Создать таблицу `my_table` Вставьте в `my_table" ценности («Состояние», «Not_Running»)

Я иду на первую вкладку браузера и доступа к сценарию. Я жду 5 секунд, перейдите на другую вкладку и доступа к сценарию, чтобы оба скрипты работали параллельно. Я ожидаю, что первая вкладка ждать, и 2-я вкладка должна выходить после 1-го запроса. Однако обе вкладки ждут линии сон (). Это означает, что первый запрос всегда возвращает «Not_running».

Некоторые странные вещи:

  • Когда я повторяю вышеуказанный эксперимент, я запускаю оба вкладка в Firefox, а затем в 3-м другом браузере, скажи Chrome, то он работает! (Состояние установлено на работу во время сна, скрипт выходит рано, когда запущен статус)
  • Когда я повторяю вышеуказанный эксперимент, используя две разные Windows командной строки и запустите скрипт из командной строки, она работает!
  • Я проверяю phpmyadmin, пока он ждет, статус обновляется правильно.

Я перепробовал все, блокируя столовую, транзакции, установите глобальную транзакционный уровень изоляции, прочитал незарегистрированное, установите AutoCommit = 1;, но всегда тот же результат.

Кто-нибудь знает, что здесь происходит? Есть ли хорошее решение для этой проблемы?

Тестированные системы: - Win, MySQL 5.0, PHP 5.3 - Linux, MySQL 5.0.91-Log, PHP 5.2.12

Я полностью застрял здесь, спасибо, что посмотрел!


ОБНОВИТЬ:

Спасибо за отправку ваших ответов - я до сих пор не могу решить эту проблему. Вот код с get_lock () и session_write_close (), как предложено: я также попробовал блокировку уровня строки, транзакции и разные уровни изоляции. Возможно, это не может быть сделано?

session_write_close (); mysql_connect ($ dbhost, $ dbusername, $ dbpassword); mysql_select_db ($ database_name); $ sql = "Create Table, если не существует` my_table` (`my_var` varchar (255) Не нулевая по умолчанию", `my_val` varchar (255) Не нулевая по умолчанию '', первичный ключ (` my_var`)) Charset по умолчанию = latin1; "; mysql_query ($ sql) или die (mysql_Error ()); mysql_query ("Выберите get_lock ('my_lock', 100)"); $ sql = "Выберите my_val из` my_table`, где `my_var` = 'status'"; RESVENT = MYSQL_UNBUFFERE_QUERY ($ SQL) или Die (mysql_Error ()); $ row = mysql_fetch_array ($ результат, mysql_assoc); Echo «Статус:». $ ряд ['my_val']. "
n "; mysql_free_result ($ result); если ($ row ['my_val'] == 'incing') умереть (процесс уже работает! '); // Ввод критического раздела $ sql =" Обновление `my_table` `my_val` =" работает ", где` my_var` = 'status' "; mysql_query ($ sql); сон (10); // сделать некоторую работу здесь. Echo 'готовая работа
'; // Оставьте критический раздел. Пусть другие знают // $ sql = "Обновить` my_pal` Установите `my_val` = 'not__running', где` my_var` = 'status' "; $ sql = "Замените в значения` my_table` (`my_var`,` my_val`) ('status', 'not__running') "; mysql_query ($ sql); $ Результат = mysql_query ($ sql) или die (mysql_Error ()); mysql_query ("Выберите release_lock ('my_lock')"); умереть();
Это было полезно?

Решение

Второе окно браузера не висит на sleep команда. Это блокировка, потому что сеансы блокируют (и, следовательно, пытаться открыть ту же сеанс). Вы можете закрыть текущий сеанс, если вам больше не нужна (и, следовательно, не хочу его блокировать) с session_write_close...

Другие советы

MySQL имеет функцию под названием Get_lock..

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top