Здравствуйте, ДимДимыч, Вы писали:
ДД>От ситуации зависит. В случае как у топикстартера, когда есть один непрерывно работающий поток, и второй — периодически модифицирующий данные, я бы использовал условную переменную для сигнализации.
Я согласен, что мой пример "синтетический" и врядли имеет отношение к жизни, я просто проиллюстрировал проблему. В реальной программе всё не совсем так, но суть остаётся такая же: потоки, у которых заведомо одинаковый приоритет, могут заблокировать друг друга.
Здравствуйте, green.nsk, Вы писали:
Pzz>>В смысле, явно переключиться туда-обратно? А почему не пару семафоров?
GN>потому что с семафорами всё также по-уродски работает
Здравствуйте, green.nsk, Вы писали:
GN>Я согласен, что мой пример "синтетический" и врядли имеет отношение к жизни, я просто проиллюстрировал проблему.
Единственная задача мютекса — предотвратить противоречивое состояние данных. Для управления планированием должны использоваться иные механизмы.
GN>В реальной программе всё не совсем так, но суть остаётся такая же: потоки, у которых заведомо одинаковый приоритет, могут заблокировать друг друга.
В данном случае они друг друга не блокируют, один ведь продолжает работать. Заблокироватся могут и с разными приоритетами, если например не соблюдают порядок захвата ресурсов.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Здравствуйте, green.nsk, Вы писали:
GN> А тут дедлок какой-то получается.
ну что-то же работает значит не deadlock
GN>Точно также не согласен с тем, что плохой дизайн — держать мутекс захваченным (почти) всё время. Могу нафантазировать кучу примеров, когда это вполне логично и эффективно.
Здравствуйте, Pzz, Вы писали:
Pzz>>>Явная бага в реализации мутексов.
А>>Почему бага?
Pzz>Потому, что и в том случае должны были бы работать оба потока. Попытка захвата мутекса должна иметь как минимум семантику вставания в очередь желающих захватить мутекс (прямо в POSIX'е этого требования нет, но оно следует из здравого смысла).
>Как максимум, должна еще учитываться проблема инверсии приоритетов — это когда более приоритетный поток вынужден слишком долго ждать менее >приоритетный, которому посчастливилось захватить мутекс первым.
а вот это в POSIX есть:
When threads executing with the scheduling policy SCHED_FIFO, SCHED_RR, or
SCHED_SPORADIC are waiting on a mutex, they shall acquire the mutex in priority order when the mutex is
unlocked.
и я думаю реализовано, и если поднять приоритет одному из них, то именно он будет держать mutex
Под MS Windows всё нормально
Стало быть, такое поведение планировщика может не всех устраивать. Возможно, поможет вызов pthread_attr_setschedpolicy с другой политикой.
Здравствуйте, green.nsk, Вы писали:
А>>кстати а почему просто не повысить приоритет потоку который никак не может захватить mutex, А>>в данном примере это не понятно какой (у меня управление получал и первый и второй), А>>но судя по описанию есть какой-то один который так и не может захватить мьютекс.
GN>А позвольте поинтересоваться Вашей конфигурацией GN>У меня на ядрах 2.6 управление получает только тот поток, который первым захватил мутекс. На ядрах 2.4 всё работает, как Вы говорите
а ядро 2.6.23 вы пробовали? у меня на нем потоки работали попеременно
Здравствуйте, mr_jek, Вы писали:
_>а вот это в POSIX есть: _> When threads executing with the scheduling policy SCHED_FIFO, SCHED_RR, or _> SCHED_SPORADIC are waiting on a mutex, they shall acquire the mutex in priority order when the mutex is _> unlocked.
_>и я думаю реализовано, и если поднять приоритет одному из них, то именно он будет держать mutex
Я не совсем про то. Если поток с низким приоритетом уже держит мутекс, и он (мутекс) понадобился потоку с высоким приоритетом, то может получиться так, что поток в высоким приоритетом ждет мутекса, а поток с низким приоритетом не получает управления (из-за своего низкого приоритета), и поэтому мутекс не отдает. Это называется инверсия приоритета.
Классическое решение заключается в том, что если поток с высоким приоритетом заблокировался на мутексе, то потоку, который мутекс в данный момент держит, временно повышают приоритет — чтобы он побыстрее кончил свои делишьки и убрался с дороги.
Здравствуйте, mr_jek, Вы писали:
GN>>Точно также не согласен с тем, что плохой дизайн — держать мутекс захваченным (почти) всё время. Могу нафантазировать кучу примеров, когда это вполне логично и эффективно.
_>давайте хотя бы один пример
Задержался с ответом, простите. Напишу псевдокодом, надеюсь, смысл донесу:
array<SOCKET> clientsArray; // сокеты, через которые происходит общение с клиентами
MUTEX clientsArrayMutex; // мутекс, который регулирует доступ к этому массиву
// Эти два сокета связываются друг с другом на стадии инициализации
SOCKET workerSender; // сокет, через который мы отправляем команды worker'у
SOCKET workerListener; // сокет, через который worker получает команды
SEMAPHORE serverPause; // семафор, на котором worker висит, когда мы хотим его "приостановить"void worker()
{
fd_set cacheFdset;
bool reloadClients = true;
while(true)
{
fd_set selectTarget;
OwnMutex(clientsArrayMutex); // захватif (reloadClients)
{
FD_ZERO(&cacheFdset);
FD_SET(workerListener, &cacheFdset);
foreach(client in clientsArray) FD_SET(client, &cacheFdset);
reloadClients = false;
}
selectTarget = cacheFdset;
int selectResult = select(selectTarget, infinite);
if (selectResult < 0) break;
foreach(client in clientsArray)
{
if (FD_ISSET(client, &selectTarget))
HandleClientActivity(client);
}
ReleaseMutex(clientsArrayMutex); // освобождениеif (FD_ISSET(workerListener, &selectTarget))
ProcessWorkerCommand();
} // while
}
// ну и напримерvoid AddClient(SOCKET newClient)
{
OwnSemaphore(serverPause);
SendCommand("reload clients");
OwnMutex(clientsArrayMutex);
clientsArray.Add(newCLient);
ReleaseMutex(clientsArrayMutex);
ReleaseSemaphore(serverPause);
}
На мой взгляд, в этом случае достаточно разумно держать мутекс "почти всё время". Конечно, здесь, в отличие от примера в первом посте, ничего плохого не произойдёт, если сервер честно висит на serverPause внутри ProcessWorkerCommand(). С указанным в первом посте примером имеет мало общего и приведён для того, чтобы подтвердить тезис о том, что "держать мутекс (почти) всё время — необязательно признак плохого дизайна".
Можно, конечно, обсуждать применение именно мутексов/семафоров в данном случае, но нафантазировать другие (более-менее классические) примитивы синхронизации, которые могут что-то сильно упростить в этом случае, у меня не получается (уж не говоря про то, что, например, в winapi набор примитивов синхронизации достаточно ограничен, а целесообразность конструирования более сложных из доступных — сомнительна).
Здравствуйте, Аноним, Вы писали:
А>а ядро 2.6.23 вы пробовали? у меня на нем потоки работали попеременно
Нет, не пробовал. К сожалению, под рукой ничего свежее 2.6.18 нет, а пересобирать ради этой фигни лень Если найду — может попробую, а так — очевидно, что исправлять в своём коде придётся. Просто порадуюсь, что в ядре всё же происходят изменения к лучшему.
Здравствуйте, Pzz, Вы писали:
Pzz>Если поток с низким приоритетом уже держит мутекс, и он (мутекс) понадобился потоку с высоким приоритетом, то может получиться так, что поток в высоким приоритетом ждет мутекса, а поток с низким приоритетом не получает управления (из-за своего низкого приоритета), и поэтому мутекс не отдает. Это называется инверсия приоритета.
Но если не ошибаюсь, такое может возникнуть только тогда, когда еще как минимум один поток с высоким приоритетом?
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Здравствуйте, ДимДимыч, Вы писали:
ДД>Но если не ошибаюсь, такое может возникнуть только тогда, когда еще как минимум один поток с высоким приоритетом?