На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются.
4. Используйте теги [ code=cpp ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Старайтесь формулировать свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной и более давности без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта (C++) user posted image FAQ Форума user posted image Наши Исходники user posted image Поиск по Разделу user posted image MSDN Library Online (Windows Driver Kit) user posted image Google

Ваше мнение о модераторах: user posted image B.V.
Модераторы: B.V.
Страницы: (4) 1 [2] 3 4  все  ( Перейти к последнему сообщению )  
> Критические секции , крэш
    CREATE_SUSPENDED активно используется в Delphi (TThread, например), т.к. при создании объекта создаётся и поток, поэтому присвоить значения полям объекта не представляется возможным иначе, как создавая поток остановленным. Однако, полагаю, что если бы не было возможности создавать поток приостановленным на старте, то это решалось бы другими способами.

    Однако у меня есть иная мысль, зачем CREATE_SUSPENDED может быть нужен.
    1. Если нужно либо создать и запустить ВСЕ потоки, либо ни одного.
    2. Если потоки активно взаимодействуют друг с другом через хендлы/id друг друга (и до запуска любого из них должен быть готовый массив хендлов всех потоков).
    3.1. Как в моём случае, если для потока нужно создать какие-либо другие объекты, которые нет смысла создавать при неудачном создании потока, но при удачном создании потока можно обойтись и без этих объектов. Особенно, если так не один Event, а ещё куча всего.
    3.2. Похожая ситуация: если действие, которое выполняется при успешном создании потока – это не просто создание ивента, которое можно откатить, а что-то более серьёзное (удаление файла, передеча по сети и пр), что нельзя так просто откатить назад при неудачном создании потока.

    Добавлено
    Цитата Олег М @
    Здесь лучше проверять, что возвращает WaitForSingleObject.
    Чем это лучше-то?

    Цитата Олег М @
    А ещё лучше, если CreateEvent вернул ошибку, вообще не запускать поток.
    Почему это?

    Добавлено
    Про CREATE_SUSPENDED:
    4. Если нужно сразу применить какие-либо свойства потоку, например, установить нужный приоритет выполнения, affinity mask.
      Цитата Qraizer @
      Как-то неубедительно. Всё это скорее "о! я придумал, где это можно применить", чем "о да, это клёвый сценарий". ID к примеру, легко заменяются инкрементируемыми для каждого потомка int-ами.

      Это не очень удачное предложение.
      Оно предполагает, что имеется только один процесс-родитель, который создаёт процессы-потомки.
      Допустим, имеется несколько независимых процессов-родителей, которые создают некоторое
      количество процессов-потомков. И какое значение int-а будет правильным ?
      Всегда правильное значение - это идентификатор процесса-потомка, он имеется у системы его я и добываю.

      Добавлено
      Цитата Jin X @
      Добавлено
      Цитата Олег М @
      Здесь лучше проверять, что возвращает WaitForSingleObject.
      Чем это лучше-то?

      Например, в результате чего-то хэндл оказался недействительным, Wait..xx вернул ошибку (никакого ожидания не будет),
      ничего не может работать правильно. В этом случае поток никогда не останавливается
      и потребляет время максимальным образом. Возможно, приложение придётся снимать внешними утилитами.
      Сообщение отредактировано: ЫукпШ -
        Цитата Jin X @
        А ещё лучше, если CreateEvent вернул ошибку, вообще не запускать поток.
        Почему это?


        Потому что, как правило, события нужны для выполнения каких-то осмысленных действий и, если объект не создался, то и запускать поток незачем.
          Цитата Олег М @
          Потому что, как правило, события нужны для выполнения каких-то осмысленных действий и,

          Нынешняя тема хорошо пересекается с недавней темой о передаче данных между потоками.
          Привожу 3-й пример, объясняющий кроме "CREATE_SUSPENDED" для чего нужен семафор.
          ---
          Делаем 2 потока (приёмник и передатчик данных) и очередь для передачи данных между ними.
          Очередь потокобезопасна, и все 3 сущности представляют собой
          экземпляры классов.
          1. Для обеспечения передачи данных передадим указатель на очередь каждому объекту-потоку.
          Уже понятно, что лучше сначала передать указатель, а потом запускать потоки.
          Поскольку одновременно при создании экземпляров классов это сделать нельзя.
          2. Хочу, чтобы при занесении данных в очередь автоматически генерировалось
          событие потоку-приёмнику. По этому событию он проснётся и начнёт работу.
          3. Для этого опишем класс-интерфейс RiseEvent c методом Rise_Event.
          4. Класс потока-приёмника унаследуем от класса-интерфейса.
          У класса-потока-приёмника появится метод Rise_Event.
          5. Классу-очереди передадим указатель на экземпляр класса-приёмника, который
          преобразуем в тип указателя на интерфейс RiseEvent.

          Теперь класс-очередь уже не просто очередь. Получился потокобезопасный коммуникационный объект.
          ---
          Итак, экземпляру класса потока-приёмника передадим указатель на очередь.
          А экземпляру класса-очереди нужен указатель на экземпляр класса-потока-приёмника.
          Это не очень удобно делать, когда поток уже запущен.
          ---
          Класс - передатчик получает данные, обрабатывает и помещает в коммуникационный
          объект. Что дальше он вообще не знает и это прекрасно ! Но он получает данные
          (допустим, из Сети) n [байт]/m [секунд]. От разных задержек и проблем "где-то там"
          может получиться и 5*n [байт]/5*m [секунд] сразу. Возможна вот такая пиковая нагрузка.
          Поток тупо соберёт данные и разместит 5 порций в очередь, которая возбудит 5 событий.
          При этом поток-приёмник не успеет обработать все сразу по мере размещения в очереди.
          Значит, надо использовать объект синхронизации, обеспечивающий
          многократное взведение/гашение. Это семафор.
          Скрытый текст

          Использовать эвент тоже можно. Для этого нужно сделать семафор из эвента программно.
            Цитата Jin X @
            Однако у меня есть иная мысль, зачем CREATE_SUSPENDED может быть нужен.
            ...
            Всё это не актуально. Просто любой CREATE_SUSPENDED легко заменяется на WaitFor...() при старте. Ну и в принципе SuspendThread()/ResumeThread() читерская штука, запросто могущая провоцировать дидлуки. Несложно придумать подобный сценарий и с CREATE_SUSPENDED.
            Цитата Jin X @
            2. Если потоки активно взаимодействуют друг с другом через хендлы/id друг друга
            Меня смущают алгоритмы, где потоки взаимодействуют друг с другом посредством явных обращений. Зачем? Это снижает гибкость архитектуры. Всегда выгоднее коммуницировать объектами синхронизации... О! Я знаю! PostThreadMessage() же! Вот где без ID нитки не обойтись. Правда, я её никогда не пользовал <_< , незачем было.
            Цитата ЫукпШ @
            Допустим, имеется несколько независимых процессов-родителей, которые создают некоторое
            количество процессов-потомков. И какое значение int-а будет правильным ?
            Нужен глобальный счётчик? Ото ты знаешь, как его оформить. Ну или в простейшем случае бери семафор. А вообще, коммуникация между родителями добавит гемора и сама по себе, так что внедрить туда ещё и счётчик на фоне этого гемора уже не будет казаться проблемой.
            Ну и в заключение. Нехрен вообще возиться со счётчиками. Создаём наследуемые неименованные объекты и передаём значения их хендлов в коммандных строках.
              Цитата ЫукпШ @
              Привожу 3-й пример, объясняющий кроме "CREATE_SUSPENDED" для чего нужен семафор.

              Не очень понял, как этот пример объясняет необходимость CREATE_SUSPENDED.

              Цитата ЫукпШ @
              3. Для этого опишем класс-интерфейс RiseEvent c методом Rise_Event.
              4. Класс потока-приёмника унаследуем от класса-интерфейса.
              У класса-потока-приёмника появится метод Rise_Event.
              5. Классу-очереди передадим указатель на экземпляр класса-приёмника, который
              преобразуем в тип указателя на интерфейс RiseEvent.


              Зачем очереди нужна ссылка на обработчик?
              Обычно для очереди делается событие, которое взводится при добавлении элемента. Обработчик потом просто ждёт это событие.
                Цитата ЫукпШ @
                Например, в результате чего-то хэндл оказался недействительным, Wait..xx вернул ошибку (никакого ожидания не будет),
                ничего не может работать правильно. В этом случае поток никогда не останавливается
                и потребляет время максимальным образом.
                Так, там же проверка статуса ещё идёт... хотя можно сделать проверку Wait'а и делать Sleep(1), чтобы не жрал в случае чего. Но с чего вдруг хендл станет недействительным?

                Цитата Олег М @
                Потому что, как правило, события нужны для выполнения каких-то осмысленных действий и, если объект не создался, то и запускать поток незачем.
                Ну это сомнительная логика. Вот к примеру, как работает та же функция EnterCriticalSection. Если секция уже захвачена и спины прокручены, она создаёт Event (если он ещё не создан). Но в случае ошибки используется NtWaitForKeyedEvent. По твоей логике Event можно было бы создавать уже в InitializeCriticalSection и сказать "ой извините, не получилось", если вдруг Event создать не получилось.
                  Цитата Jin X @
                  Ну это сомнительная логика. Вот к примеру, как работает та же функция EnterCriticalSection. Если секция уже захвачена и спины прокручены, она создаёт Event. Но в случае ошибки используется NtWaitForKeyedEvent. По твоей логике Event можно было бы создать уже в InitializeCriticalSection и сказать "ой извините, не получилось", если вдруг Event создать не получилось.

                  Ну да, создавать именно там и надо, в InitializeCriticalSection. Ошибку при этом можно не выдавать.
                    Цитата Олег М @
                    Ну да, создавать именно там и надо, в InitializeCriticalSection. Ошибку при этом можно не выдавать.
                    А я думаю, что это сделано намеренно, чтобы не создавать лишних объектов, которые могут не понадобиться (и в 99% случаев не надобятся).
                      Цитата Jin X @
                      А я думаю, что это сделано намеренно, чтобы не создавать лишних объектов, которые могут не понадобиться (и в 99% случаев не надобятся).

                      В случае с критической секцией как раз наоборот - в 99% случаев понадобится.
                      Да и вообще, лучше узнать о возможных проблемах сразу при создании объекта, чем когда-то потом.
                      Что-то я сомневаюсь, что NtWaitForKeyedEvent работает эффективнее, чем просто событие.
                        Цитата Олег М @
                        В случае с критической секцией как раз наоборот - в 99% случаев понадобится.
                        Не думаю. Сильно зависит от задачи. Но что-то мне подсказывает, что в большинстве задач чаще нет, чем да.
                          Тут следует учесть, что назначением критических секций является служить лёгкой заменой мьютексам, которые, будучи объектами ядра, довольно тяжелы. Зачастую программистам требуется защитить малые и быстрые участки кода от параллельного исполнения, в которых ожидается в среднем малая вероятность коллизий, но таких участков может быть очень много разных, и они все заключены в одном приложении, что не требует межпроцессного осблуживания. Типичный пример – стандартные библиотечные функции, которые живут в языке с 70-ых годов прошлого века и манипулируют глобальными объектами и признаками, что в то время являлось нормальным, однако плохо совместимым в многопоточном окружении. Сейчас их уже не переделаешь, они глубоко завязли в Стандарте языка. Естественно, защищать от коллизий всякие там malloc(), printf(), asctime(), strtok() итп нужно, иначе будет хаос, но коллизии для них ожидаются очень редкими, поэтому защищая их объектами ядра, можно ожидать крайне большой потери производительности. К тому же, много объектов ядра, по одному на каждую функцию, сильно утяжелит требования приложений к ресурсам ОС, в особенности, если такие требования будет предъявлять большое число приложений.
                          Критические секции спроектированы как лёгкие объекты синхронизации. При отсутствии коллизий они требуют лишь пары десятков ассемблерных инструкций, исполняемых к тому же целиком в режиме пользователя, без переключения в ядро, а требуемые ими ресурсы ограничиваются ресурсами самого приложения, а не ОС. При отсутствии коллизий, особенно в многоядерных процессорах, где критические секции даже при наличии коллизий могут реализовать относительно короткие циклы ожидания через спин-блокировки, объект ядра запросто может быть так и не востребован ни разу. Увы, это же и означает, что захват критической секции может оказаться невозможным, если она ещё не имеет связанного объекта ядра, однако столкнулась с коллизией, с которой спин-блокировка не справилась, но у ОС тупо кончились ресурсы.
                            Цитата Qraizer @
                            Увы, это же и означает, что захват критической секции может оказаться невозможным, если она ещё не имеет связанного объекта ядра, однако столкнулась с коллизией, с которой спин-блокировка не справилась, но у ОС тупо кончились ресурсы.
                            Да почему же? Когда кончаются ресурсы, используется KeyedEvent, так что тут проблем тоже нет...

                            Добавлено
                            Глянь https://doxygen.reactos.org/d0/d06/critical_8c_source.html
                            В RtlpWaitForCriticalSection (который вызывается из RtlEnterCriticalSection) используется NtWaitForKeyedEvent:
                            ExpandedWrap disabled
                                150         if (CriticalSection->LockSemaphore == INVALID_HANDLE_VALUE)
                                151         {
                                152             /* Use the global keyed event (NULL as keyed event handle) */
                                153             Status = NtWaitForKeyedEvent(NULL,
                                154                                          CriticalSection,
                                155                                          FALSE,
                                156                                          &RtlpTimeout);
                                157         }
                                158         else
                                159         {
                                160             /* Wait on the Event */
                                161             Status = NtWaitForSingleObject(CriticalSection->LockSemaphore,
                                162                                            FALSE,
                                163                                            &RtlpTimeout);
                                164         }
                              Эти события недокументированы. Они были предназначены для единственной цели – гарантировать отсутствие отказов при использовании критических секций. Начиная с WinXP, эта гарантия имеется, до этого следовало самостоятельно ловить SEH-исключения.

                              Добавлено
                              Keyed Events
                              Сообщение отредактировано: Qraizer -
                                А зачем их документировать, если они используются внутри системы?

                                Цитата Qraizer @
                                Они были предназначены для единственной цели – гарантировать отсутствие отказов при использовании критических секций.
                                Ну, а ты говоришь что захват может оказаться невозможным. Ты про Win2K ?
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (4) 1 [2] 3 4  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0542 ]   [ 17 queries used ]   [ Generated: 28.03.24, 17:40 GMT ]