The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  ВХОД  слежка  RSS
"Вопросец"
Вариант для распечатки Архивированная нить - только для чтения! 
Пред. тема | След. тема 
Форумы Программирование под UNIX (Public)
Изначальное сообщение [Проследить за развитием треда]

"Вопросец"
Сообщение от sproot Искать по авторуВ закладки(ok) on 07-Дек-04, 10:21  (MSK)
Почему на RedHat 8 криво работает данный код:
=========================================
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <semaphore.h>
#include <sys/mman.h>


struct shared {
    int count;
};

int main(void)
{
    int fd, i, nloop=50;
    struct shared *ptr;
    sem_t mutex;
    
    fd = open("/dev/zero", O_RDWR);
    if (fd < 0) printf("Error open /dev/zero\n");
else printf("Succes open /dev/zero\n");

    ptr = mmap(NULL, sizeof(struct shared), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    
    sem_init(&mutex, 0, 1);

    setbuf(stdout, NULL);
            
    if ( fork() == 0) {
for (i = 0; i < nloop; i++) {
    sem_wait(&mutex);
    printf("child: \n");
    sem_post(&mutex);
}
exit(0);
    }

    for (i = 0; i < nloop; i++) {
    sem_wait(&mutex);
    printf("parent: %d\n", ptr->count++);
    sem_post(&mutex);
    }
exit(0);
}
=========================================
Приблизительно из 20 попыток 1 раз выводиться child... во всех остальных parent.На RedHat 9 такой проблемы нет.

  Рекомендовать в FAQ | Cообщить модератору | Наверх

 Оглавление

Индекс форумов | Темы | Пред. тема | След. тема
Сообщения по теме

1. "Вопросец"
Сообщение от sproot Искать по авторуВ закладки(ok) on 07-Дек-04, 10:31  (MSK)
поправка...не 1 раз child, а вместе с child
  Рекомендовать в FAQ | Cообщить модератору | Наверх

2. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 00:21  (MSK)
А в чем проблема?
Разве sem_wait/sem_post гарантируют порядок взятия семафора?
В man по этому поводу ничего не могу найти.
  Рекомендовать в FAQ | Cообщить модератору | Наверх

3. "Вопросец"
Сообщение от sproot Искать по авторуВ закладки(ok) on 08-Дек-04, 00:51  (MSK)
>А в чем проблема?
>Разве sem_wait/sem_post гарантируют порядок взятия семафора?
>В man по этому поводу ничего не могу найти.
Естественно гарантируют "по определению", это атомарная операция.
Глюк был в том что нужно было задать nloop по больше (например 10000).
сейчас вопрос в другом, почему если
=============
.....
if ( fork() == 0) {
        for (i = 0; i < nloop; i++) {
            sem_wait(&mutex);
            printf("child: %d\n", ptr->count++);
            sem_post(&mutex);
        }
        exit(0);
    }

    for (i = 0; i < nloop; i++) {
            sem_wait(&mutex);
            printf("parent: %d\n", ptr->count++);
            sem_post(&mutex);
    }
.........
================================

на местах состыковки parent и child номера счетчика count не идут попорядку, хотя буферизация вывода отключена setbuf(stdout, NULL); ?

  Рекомендовать в FAQ | Cообщить модератору | Наверх

4. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 01:13  (MSK)
>>А в чем проблема?
>>Разве sem_wait/sem_post гарантируют порядок взятия семафора?
>>В man по этому поводу ничего не могу найти.
>Естественно гарантируют "по определению", это атомарная операция.

А что неатомарного в том, что семафор может какое-угодно число раз подряд браться и отпускаться в одной нити даже если на нем кто-то еще ждет в другой? Грубо говоря, нет никакого порядка, в котором должен быть виден вывод.

>Глюк был в том что нужно было задать nloop по больше (например
>10000).

Глюк чего? Был написан нормальный корректный код, для которого не определен порядок вывода. Этот порядок точно так же неопределен при любом n. Так что даже не знаю, что вы там "исправили". :)

  Рекомендовать в FAQ | Cообщить модератору | Наверх

6. "Вопросец"
Сообщение от sproot Искать по авторуВ закладки(ok) on 08-Дек-04, 01:24  (MSK)
А разве count не должен идти попорядку ? Какая разница какой поток вызывает printf, он выводит в stdout последовательные значения и причем без буферизации.

>Глюк чего? Был написан нормальный корректный код, для которого не >определен порядок вывода. Этот порядок точно так же неопределен при >любом n. Так что даже не знаю, что вы там "исправили". :)
ну ладно, не глюк - недосмотр.

  Рекомендовать в FAQ | Cообщить модератору | Наверх

8. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 01:27  (MSK)
>ну ладно, не глюк - недосмотр.


В оригинальном сообщении ничего не было про разрыв в значениях.
А порядок взятия семафора не определен. Т.е. сколько будет parent подряд и сколько child подряд - как повезет.

По поводу count - должно быть все ок. В этом отношении код корректен (если мьютекс используется корректно).

  Рекомендовать в FAQ | Cообщить модератору | Наверх

10. "Вопросец"
Сообщение от sproot Искать по авторуВ закладки(ok) on 08-Дек-04, 01:29  (MSK)
>>ну ладно, не глюк - недосмотр.
>
>
>В оригинальном сообщении ничего не было про разрыв в значениях.
>А порядок взятия семафора не определен. Т.е. сколько будет parent подряд и
>сколько child подряд - как повезет.
>
>По поводу count - должно быть все ок. В этом отношении код
>корректен (если мьютекс используется корректно).
Я может быть еще раз повторюсь...какая разница кто увеличивает счетчик ?
при выводе значения счетчика должны идти попорядку
  Рекомендовать в FAQ | Cообщить модератору | Наверх

15. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 01:44  (MSK)
Жутко извиняюсь, я невнимательно смотрел - счетчик ведь увеличивает только одна нить, т.е. счетчик трогает только один процесс/нить. Все должно быть ок. У меня всё идет подряд. :( Была бы проблема одновременного доступа, если бы несколько нитей трогали счетчик.

Приведите пример, как у вас не подряд идут значения.

  Рекомендовать в FAQ | Cообщить модератору | Наверх

16. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 01:53  (MSK)
Давайте по порядку.

Есть два куска кода - первый и второй.

В первом фактически имеется один доступ к переменной - никаких проблем нет. Порядок, в котором выводится parent и child, вроде как не определен. Мы в этом согласились?

Во втором, поскольку мьютекс так странно используется (нет pshared=1), то идет одновременный (несинхронизированный) доступ к переменным. Это приводит к проблемы в SMP, поскольку цикл чтение, увеличение, запись в память - неатомарный. В UP могут быть проблемы, если процессор увеличивает счетчик
не одной операцией (например, кэширует переменную в регистрах и неатомарность происходит не за счет races на шине, а за счет race condition в обновлении ячейки памяти со значением).

  Рекомендовать в FAQ | Cообщить модератору | Наверх

17. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 01:58  (MSK)
У меня машина - UP и GCC генерирует одну инструкцию для counter++:

        printf("parent: %d\n", ptr->count++);
080486d0 <main+0x124> sub    esp,0x8
080486d3 <main+0x127> mov    eax,DWORD PTR [ebp-24]
080486d6 <main+0x12a> mov    edx,DWORD PTR [eax]
080486d8 <main+0x12c> push   edx
080486d9 <main+0x12d> inc    DWORD PTR [eax]
080486db <main+0x12f> push   0x8048828
080486e0 <main+0x134> call   080484d4 <printf@plt>
080486e5 <main+0x139> add    esp,0x10

поэтому, вероятно, всё хорошо.

  Рекомендовать в FAQ | Cообщить модератору | Наверх

19. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 02:02  (MSK)
>У меня машина - UP и GCC генерирует одну инструкцию для counter++:
>
>
>        printf("parent: %d\n", ptr->count++);
>080486d0 <main+0x124> sub    esp,0x8
>080486d3 <main+0x127> mov    eax,DWORD PTR [ebp-24]
>080486d6 <main+0x12a> mov    edx,DWORD PTR [eax]
>080486d8 <main+0x12c> push   edx
>080486d9 <main+0x12d> inc    DWORD PTR [eax]
>080486db <main+0x12f> push   0x8048828
>080486e0 <main+0x134> call   080484d4 <printf@plt>
>080486e5 <main+0x139> add    esp,0x10
>
>поэтому, вероятно, всё хорошо.


Кстати, есть еще небольшой race condition между толканием counter в стек и увеличением на 1. В общем, все проблемы - от отсутствия синхронизации (такого странного использования mutex).

  Рекомендовать в FAQ | Cообщить модератору | Наверх

18. "Вопросец"
Сообщение от sproot Искать по авторуВ закладки(ok) on 08-Дек-04, 01:59  (MSK)
У меня вывод такой:
..............
parent: 347
child: 349
child: 350
child: 351
child: 352
child: 353
.............
child: 439
child: 440
child: 441
parent: 348
parent: 443
parent: 444
parent: 445
.................

  Рекомендовать в FAQ | Cообщить модератору | Наверх

20. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 02:05  (MSK)
А ... ну тут самый очевидный race.
Смотрите:
вы увеличиваете на 1 counter, пихаете его в стек и вызываете printf.
Внутри printf происходит перепланированием, выполняется child, потом происходит перепланирование и вы возвращаетесь в printf в parent и завершаете вывод старого (запиханного на стек значения).

>У меня вывод такой:
>..............
>parent: 347
>child: 349
>child: 350
>child: 351
>child: 352
>child: 353
>.............
>child: 439
>child: 440
>child: 441
>parent: 348
>parent: 443
>parent: 444
>parent: 445
>.................


  Рекомендовать в FAQ | Cообщить модератору | Наверх

22. "Вопросец"
Сообщение от sproot Искать по авторуВ закладки(ok) on 08-Дек-04, 02:13  (MSK)
>А ... ну тут самый очевидный race.
>Смотрите:
>вы увеличиваете на 1 counter, пихаете его в стек и вызываете printf.
>
>Внутри printf происходит перепланированием, выполняется child, потом происходит перепланирование и вы возвращаетесь
>в printf в parent и завершаете вывод старого (запиханного на стек
>значения).
>
>>У меня вывод такой:
>>..............
>>parent: 347
>>child: 349
>>child: 350
>>child: 351
>>child: 352
>>child: 353
>>.............
>>child: 439
>>child: 440
>>child: 441
>>parent: 348
>>parent: 443
>>parent: 444
>>parent: 445
>>.................

Теперь понятно, где собака зарыта

  Рекомендовать в FAQ | Cообщить модератору | Наверх

5. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 01:17  (MSK)
Понял в чем твоя проблема - в неумении читать man.
Там же черным по белому написано, что в LinuxThreads не реализован pshared=1.
  Рекомендовать в FAQ | Cообщить модератору | Наверх

7. "Вопросец"
Сообщение от sproot Искать по авторуВ закладки(ok) on 08-Дек-04, 01:26  (MSK)
>Понял в чем твоя проблема - в неумении читать man.
>Там же черным по белому написано, что в LinuxThreads не реализован pshared=1.
>
Это как раз-то ты не умеешь читать man. pshared задаеться вторым параметром а он у меня =0
  Рекомендовать в FAQ | Cообщить модератору | Наверх

9. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 01:28  (MSK)
>Это как раз-то ты не умеешь читать man. pshared задаеться вторым параметром
>а он у меня =0


Ууу... точно. Тогда код точно в топку. Заводим два семафора - на parent и child и еще что-то хотим от них.

  Рекомендовать в FAQ | Cообщить модератору | Наверх

11. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 01:31  (MSK)
>>Это как раз-то ты не умеешь читать man. pshared задаеться вторым параметром
>>а он у меня =0
>
>
>Ууу... точно. Тогда код точно в топку. Заводим два семафора - на
>parent и child и еще что-то хотим от них.


Теоретически там происходит банальный race condition, поскольку
counter++ - неатомарная операция, поскольку процессор скорее всего считает
через регистры, ну плюс еще куча моментов для SMP.

  Рекомендовать в FAQ | Cообщить модератору | Наверх

12. "Вопросец"
Сообщение от sproot Искать по авторуВ закладки(ok) on 08-Дек-04, 01:36  (MSK)
>Теоретически там происходит банальный race condition, поскольку
>counter++ - неатомарная операция, поскольку процессор скорее всего считает
>через регистры, ну плюс еще куча моментов для SMP.
Тогда чем лучше делать синхронизацию между дочерними процессами ?
Может быть именованными семафорами Posix? или семафорами System V ?
  Рекомендовать в FAQ | Cообщить модератору | Наверх

13. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 01:40  (MSK)
>Тогда чем лучше делать синхронизацию между дочерними процессами ?
>Может быть именованными семафорами Posix? или семафорами System V ?

System V должны работать всегда. Эти семафоры тоже должны работать в NPTL с pshared=1 (в RH9).

  Рекомендовать в FAQ | Cообщить модератору | Наверх

14. "Вопросец"
Сообщение от sproot Искать по авторуВ закладки(ok) on 08-Дек-04, 01:44  (MSK)
>>Тогда чем лучше делать синхронизацию между дочерними процессами ?
>>Может быть именованными семафорами Posix? или семафорами System V ?
>
>System V должны работать всегда. Эти семафоры тоже должны работать в NPTL
>с pshared=1 (в RH9).
Хорошо попробую.Спасибо за подсказки. Без обид.

  Рекомендовать в FAQ | Cообщить модератору | Наверх

21. "Вопросец"
Сообщение от Murr Искать по авторуВ закладки(??) on 08-Дек-04, 02:08  (MSK)
>>>Тогда чем лучше делать синхронизацию между дочерними процессами ?
>>>Может быть именованными семафорами Posix? или семафорами System V ?
>>
>>System V должны работать всегда. Эти семафоры тоже должны работать в NPTL
>>с pshared=1 (в RH9).
>Хорошо попробую.Спасибо за подсказки. Без обид.

Эээ... это я сам извиняюсь. Нормальный у вас код, просто pshared не указали - вот и проблема с доступом к counter, а так все нормально.

P.S. Голова болит :(

  Рекомендовать в FAQ | Cообщить модератору | Наверх


Удалить

Индекс форумов | Темы | Пред. тема | След. тема
Пожалуйста, прежде чем написать сообщение, ознакомьтесь с данными рекомендациями.




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2025 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру