Qt QSemaphore release () не сразу уведомляет официантов? - PullRequest
2 голосов
/ 04 ноября 2011

Я написал консольное приложение Qt, чтобы опробовать QSemaphores, и заметил странное поведение.Рассмотрим семафор с 1 ресурсом и двумя потоками, получающими и освобождающими один ресурс.Псевдокод:

QSemaphore sem(1);   // init with 1 resource available

thread1()
{
    while(1)
    {
        if ( !sem.tryAquire(1 resource, 1 second timeout) )
        {
            print "thread1 couldn't get a resource";
        }
        else
        {
            sem.release(1);
        }
    }
}

// basically the same thing
thread2()
{
    while(1)
    {
        if ( !sem.tryAquire(1 resource, 1 second timeout) )
        {
            print "thread2 couldn't get a resource";
        }
        else
        {
            sem.release(1);
        }
    }
}

Кажется простым, но потокам часто не удается получить ресурс.Чтобы исправить это, нужно немного перевести поток в режим сна после sem.release(1).Это говорит мне о том, что член release() не позволяет другим потокам, ожидающим в tryAquire(), получить доступ к семафору, прежде чем текущий поток вернется к вершине while(1) и снова захватит ресурс.Это удивляет меня, потому что подобное тестирование с QMutex показало правильное поведение ... то есть другой поток, зависающий в QMutex::tryLock(timeout), получает уведомление правильно, когда вызывается QMutex::unlock().

Есть идеи?

1 Ответ

2 голосов
/ 04 ноября 2011

Я не могу полностью проверить это или найти все вспомогательные ссылки в данный момент, но вот несколько замечаний ...

Во-первых, документация для QSemaphore.tryAcquire указывает, что значение тайм-аута составляет миллисекунды , а не секунды. Таким образом, ваши потоки ожидают освобождения ресурса всего 1 миллисекунду.

Во-вторых, я вспоминаю, как где-то читал (к сожалению, не помню где) обсуждение того, что происходит, когда несколько потоков пытаются получить один и тот же ресурс одновременно. Хотя поведение может варьироваться в зависимости от ОС и ситуации, казалось, что типичным результатом является то, что он является общедоступным, и ни одному потоку не предоставляется более высокий приоритет, чем другому. Таким образом, поток, ожидающий получения ресурса, будет иметь такой же шанс получить его, как и поток, который только что выпустил его и пытается немедленно повторно получить его. Я не уверен, что настройка приоритета потока повлияет на это.

Итак, почему вы можете получить разные результаты для QSemaphore и QMutex? Ну, я думаю, что семафор может быть более сложным системным ресурсом, который потребует больше времени для получения и выпуска, чем мьютекс. Недавно я сделал несколько простых временных интервалов для мьютексов и обнаружил, что в среднем на блокировку или разблокировку уходит около 15-25 микросекунд. В течение 1 миллисекунды, которую ожидают ваши потоки, это будет не менее 20 циклов блокировки и разблокировки, и шансы одного и того же потока всегда повторно захватывать блокировку в это время невелики. Ожидающий поток, скорее всего, получит хотя бы один кусочек от яблока за время ожидания, поэтому при использовании мьютексов в вашем примере вы, скорее всего, не увидите никаких ошибок получения.

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

...