pthread mutex concurrent threads
От: mc-Duck  
Дата: 25.10.07 08:00
Оценка:
Здравствуйте все.

Сразу прошу извинить меня, если баян, поиск почему-то отказался мне помочь.

Я вообще редко пишу под *nix, но когда приходится, меня вообще часто радуют странным поведением библиотечные функции. Этот раз тоже не стал исключением

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

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* threadfunc(void * str)
{
        printf("starting thread %s", str);
        while (true)
        {
                pthread_mutex_lock(&mutex);
                printf((char *)str);
                sleep(2);
                pthread_mutex_unlock(&mutex);
        }

        return 0;
}

int main()
{
        pthread_t thread1, thread2;
        pthread_create(&thread1, 0, threadfunc, (void*)"thread1\n");

        sleep(1);

        pthread_create(&thread2, 0, threadfunc, (void*)"thread2\n");

        sleep(100);

        // здесь должна быть остановка потоков, но непринципиально

        return 0;

}


Эта программа ни разу не даёт потоку thread2 захватить мутекс. Я понимаю, что нельзя ожидать того, что они будут захватывать мутекс по очереди, но я ведь вправе рассчитывать, что каждый поток в принципе получит доступ к нему? Если нет — то вообще на кой такой примитив синхронизации нужен?

Это лыжи не едут или я ...?

PS проверял на
Linux system 2.6.16-2-xen-amd64-k8 #1 SMP Sun Jul 16 03:25:55 CEST 2006 x86_64 GNU/Linux
Linux system 2.6.9-5.EL #1 Wed Jan 5 19:22:18 EST 2005 i686 i686 i386 GNU/Linux
Re: pthread mutex concurrent threads
От: mc-Duck  
Дата: 25.10.07 08:09
Оценка:
нашёл покрытую плесенью тачку с ядром 2.4.32 — работает как ожидалось. даже ровно по очереди захваты случаются
Re: pthread mutex concurrent threads
От: Аноним  
Дата: 25.10.07 10:34
Оценка: 1 (1)
Здравствуйте, mc-Duck, Вы писали:


MD>void* threadfunc(void * str)

MD>{
MD> printf("starting thread %s", str);
MD> while (true)
MD> {
MD> pthread_mutex_lock(&mutex);
MD> printf((char *)str);
MD> sleep(2);
MD> pthread_mutex_unlock(&mutex);
MD> }

MD> return 0;

MD>}

здесь поможет pthread_yield() после защищенной секции
Re: pthread mutex concurrent threads
От: citrin Россия http://citrin.ru/
Дата: 25.10.07 10:35
Оценка:
MD>
MD>        while (true)
MD>        {
MD>                pthread_mutex_lock(&mutex);
MD>                printf((char *)str);
MD>                sleep(2);
MD>                pthread_mutex_unlock(&mutex);
MD>        }


Получается что lock происходит сразу же после unlock, и другой поток просто не успевает ничего сделать.
Поставьте sleep(1) после unlock и они будут по очеред захватывать мьютекс.
Re[2]: pthread mutex concurrent threads
От: Аноним  
Дата: 25.10.07 10:44
Оценка:
Здравствуйте, Аноним, Вы писали:

кстати, вопрос насколько данный пример корректен,
спать имея блокировку довольно странно, а если убрать "sleep",
то все работает,

кстати а почему просто не повысить приоритет потоку который никак не может захватить mutex,
в данном примере это не понятно какой (у меня управление получал и первый и второй),
но судя по описанию есть какой-то один который так и не может захватить мьютекс.
Re[2]: pthread mutex concurrent threads
От: Аноним  
Дата: 25.10.07 10:50
Оценка:
Здравствуйте, citrin, Вы писали:

MD>>
MD>>        while (true)
MD>>        {
MD>>                pthread_mutex_lock(&mutex);
MD>>                printf((char *)str);
MD>>                sleep(2);
MD>>                pthread_mutex_unlock(&mutex);
MD>>        }
C>


C>Получается что lock происходит сразу же после unlock, и другой поток просто не успевает ничего сделать.

C>Поставьте sleep(1) после unlock и они будут по очеред захватывать мьютекс.

здесь все немного хитрее на мой взгляд,
даже если один поток не успевает, то все равно кванты времени отпущенные первому должны истечь,
и управление на некоторое время получит другой,
но т.к. во время sleep кванты времени не тратяться, то субьективно времени прошло много и кванты не истекли,
а объективно у потока еще осталось время.
Re: pthread mutex concurrent threads
От: Pzz Россия https://github.com/alexpevzner
Дата: 25.10.07 10:55
Оценка:
MD>В моей программе есть несколько потоков, один из них работает с какими-то данными, второй иногда (редко) пытается эти данные модифицировать. Для разграничения доступа я навесил на данные мутекс. Однако, получилось, что второй поток вообще не может получить доступа к данным. Я попытался воспроизвести ситуацию в тестовом примере и вот что у меня получилось:

Прикольно, да. Явная бага в реализации мутексов.

Однако бага проявляется только если один из потоков держит мутекс практически 100% времени. Это явный дефект дизайна программы, так быть не должно.
Re[2]: pthread mutex concurrent threads
От: Аноним  
Дата: 25.10.07 11:41
Оценка: +1
Здравствуйте, Pzz, Вы писали:

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


Pzz>Явная бага в реализации мутексов.


Почему бага?

Вот например в таком случае работают оба потока:



static volatile int m;

void* threadfunc(void * str)
{
    int i;
        printf("starting thread %s", (char *)str);
        while (1)
        {
                pthread_mutex_lock(&mutex);
                printf((char *)str);
//                sleep(2);
        for (i = 0; i < 1000; ++i)
            ++m;
                pthread_mutex_unlock(&mutex);
        }

        return 0;
}
Re[3]: pthread mutex concurrent threads
От: Pzz Россия https://github.com/alexpevzner
Дата: 25.10.07 11:54
Оценка: +1
Pzz>>Явная бага в реализации мутексов.

А>Почему бага?


Потому, что и в том случае должны были бы работать оба потока. Попытка захвата мутекса должна иметь как минимум семантику вставания в очередь желающих захватить мутекс (прямо в POSIX'е этого требования нет, но оно следует из здравого смысла). Как максимум, должна еще учитываться проблема инверсии приоритетов — это когда более приоритетный поток вынужден слишком долго ждать менее приоритетный, которому посчастливилось захватить мутекс первым.
Re[4]: pthread mutex concurrent threads
От: ДимДимыч Украина http://klug.org.ua
Дата: 25.10.07 12:11
Оценка: -1
Здравствуйте, Pzz, Вы писали:

А>>Почему бага?

Pzz>Потому, что и в том случае должны были бы работать оба потока.

Если обеспечиваемая потоками функциональность идентична, то ИМХО с точки зрения затрачиваемых ресурсов дешевле отпускать один и тот же поток. А вот решение об идентичности функциональности должен принимать программист и с учетом этого выбирать методы синхронизации.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[5]: pthread mutex concurrent threads
От: Pzz Россия https://github.com/alexpevzner
Дата: 25.10.07 12:15
Оценка:
ДД>Если обеспечиваемая потоками функциональность идентична, то ИМХО с точки зрения затрачиваемых ресурсов дешевле отпускать один и тот же поток. А вот решение об идентичности функциональности должен принимать программист и с учетом этого выбирать методы синхронизации.

И какие существуют в природе методы синхронизации, обеспечивающие семантику мутекса, и при этом гарантирующие, что потоки будут исполняться по-очереди, а не "кто первый встал, того и тапки"?
Re[6]: pthread mutex concurrent threads
От: green.nsk  
Дата: 25.10.07 12:31
Оценка:
Pzz>И какие существуют в природе методы синхронизации, обеспечивающие семантику мутекса, и при этом гарантирующие, что потоки будут исполняться по-очереди, а не "кто первый встал, того и тапки"?

Ну на самом деле, я думаю, можно придумать как, комбинируя мутексы, добиться "честного" шедулинга. Другой вопрос в принципе — на кой нам ОС если честный шедулер приходится писать руками?
Re[2]: pthread mutex concurrent threads
От: green.nsk  
Дата: 25.10.07 12:39
Оценка:
Здравствуйте, citrin, Вы писали:

C>Получается что lock происходит сразу же после unlock, и другой поток просто не успевает ничего сделать.

C>Поставьте sleep(1) после unlock и они будут по очеред захватывать мьютекс.

это поможет починить конкретный пример. проблема же в том, что так ведь не должно быть, должно всё нормально и без sleep работать, так? или я что-то не понимаю?
Re[3]: pthread mutex concurrent threads
От: green.nsk  
Дата: 25.10.07 12:41
Оценка:
А>кстати а почему просто не повысить приоритет потоку который никак не может захватить mutex,
А>в данном примере это не понятно какой (у меня управление получал и первый и второй),
А>но судя по описанию есть какой-то один который так и не может захватить мьютекс.

А позвольте поинтересоваться Вашей конфигурацией
У меня на ядрах 2.6 управление получает только тот поток, который первым захватил мутекс. На ядрах 2.4 всё работает, как Вы говорите
Re[6]: pthread mutex concurrent threads
От: ДимДимыч Украина http://klug.org.ua
Дата: 25.10.07 12:42
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>И какие существуют в природе методы синхронизации, обеспечивающие семантику мутекса, и при этом гарантирующие, что потоки будут исполняться по-очереди, а не "кто первый встал, того и тапки"?


От ситуации зависит. В случае как у топикстартера, когда есть один непрерывно работающий поток, и второй — периодически модифицирующий данные, я бы использовал условную переменную для сигнализации.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[7]: pthread mutex concurrent threads
От: Pzz Россия https://github.com/alexpevzner
Дата: 25.10.07 12:43
Оценка:
Здравствуйте, green.nsk, Вы писали:

Pzz>>И какие существуют в природе методы синхронизации, обеспечивающие семантику мутекса, и при этом гарантирующие, что потоки будут исполняться по-очереди, а не "кто первый встал, того и тапки"?


GN>Ну на самом деле, я думаю, можно придумать как, комбинируя мутексы, добиться "честного" шедулинга.


Эээ. Ну да, наверное из 2-х линуксячих мутексов можно сделать один нормальный, организовав очередь вручную.

GN>Другой вопрос в принципе — на кой нам ОС если честный шедулер приходится писать руками?


На кой нам ОС с багами? Ну наверное затем, что не все в ней — баги.
Re[7]: pthread mutex concurrent threads
От: Pzz Россия https://github.com/alexpevzner
Дата: 25.10.07 12:45
Оценка:
Здравствуйте, ДимДимыч, Вы писали:

ДД>От ситуации зависит. В случае как у топикстартера, когда есть один непрерывно работающий поток, и второй — периодически модифицирующий данные, я бы использовал условную переменную для сигнализации.


В смысле, явно переключиться туда-обратно? А почему не пару семафоров?
Re[5]: pthread mutex concurrent threads
От: green.nsk  
Дата: 25.10.07 12:45
Оценка:
Здравствуйте, ДимДимыч, Вы писали:

ДД>Если обеспечиваемая потоками функциональность идентична, то ИМХО с точки зрения затрачиваемых ресурсов дешевле отпускать один и тот же поток. А вот решение об идентичности функциональности должен принимать программист и с учетом этого выбирать методы синхронизации.


Алгоритмически, может и правда проще, не знаю, не занимался.
Но ведь логично реализовать не самую простую схему, а самую полезную, так? На мой взгляд, самая полезная (и "честная" чтоли) схема, это когда примитив захватывает тот, кто первым попытался его захватить. Ну или, по крайней мере, все, должны получать одинаковые возможности. А тут дедлок какой-то получается.

Точно также не согласен с тем, что плохой дизайн — держать мутекс захваченным (почти) всё время. Могу нафантазировать кучу примеров, когда это вполне логично и эффективно.
Re[4]: pthread mutex concurrent threads
От: Pzz Россия https://github.com/alexpevzner
Дата: 25.10.07 12:47
Оценка:
Здравствуйте, green.nsk, Вы писали:

GN>А позвольте поинтересоваться Вашей конфигурацией

GN>У меня на ядрах 2.6 управление получает только тот поток, который первым захватил мутекс. На ядрах 2.4 всё работает, как Вы говорите

На 2.4 мутексы работают совсем по-другому, чем на 2.6. На 2.6 потоки сами между собой разбираются с помощью futex'а, на 2.4 используется отдельный служебный поток, который решает, кого разбудить.
Re[8]: pthread mutex concurrent threads
От: green.nsk  
Дата: 25.10.07 12:48
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>В смысле, явно переключиться туда-обратно? А почему не пару семафоров?


потому что с семафорами всё также по-уродски работает
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.