На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
  
> Неблокирующий ввод вывод в Linux
    Доброго времени суток.

    Вопрос про кросплатформенное программирование, код на FreePascal/Lazarus, но сам вопрос скорее про Linux, поэтому я как-то даже теряюсь в каком разделе спрашивать. Впринципе знаю C/C++ поэтому перевести с одного языка на другой проблем не составит.

    Есть код под Windows для обмена с COM-портом использующий Overlapped запись/чтение и дальнейшее ожидание пришедших данных с использованием WinApi WaitForMultipleObjects. Код выполняется в отдельном потоке. Пытаюсь перевести его под Linux. Загвостка в том что этот WaitForMultipleObjects используется для ожидания двух Event'ов - один от ввода/вывода, другой - для оповещения потока о завершении приложения. Вычитал что под Linux есть неблокирующие операции ввода вывода, но как я понял select не позволяет ожидать какие-либо события помимо ввода вывода (мб плохо читал?). aio_... в fpc не нашел, поэтому остановился именно на неблокирующих операциях. Также вычитал что в Linux можно назначить процедуру, которая будет вызываться при запросе на завершение потока, но я так понимаю что она скорее всего будет задействована какими-то внутренними механизмами встроенной библиотеки компилятора, поэтому её использование не желательно.

    Сам в Linux не силен от слова совсем, может кто подскажет как из этого лучше выкрутиться или ткнёт что почитать.

    Код под Windows прилагаю. Подрезал чтобы не такая большая "простыня" была, но впринципе в нём нет ничего особенного.
    ExpandedWrap disabled
      const
        DEADLOCK_TIMEOUT = 60000;
        BUFSIZE = 512;
      var
        buf: array [0..BUFSIZE-1] of Byte;
        cb: DCB;
        ct: COMMTIMEOUTS;
        ov: OVERLAPPED;
        hPort: THandle;
        hCancelEvent: THandle;
        wo: array [0..1] of THandle;
        bRet: BOOL;
        nRet: DWORD;
        dwBytesRead: DWORD;
      begin
        hPort := CreateFile('\\.\COM1', GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
        try
          ov.Internal := 0;
          ov.InternalHigh := 0;
          ov.Offset := 0;
          ov.OffsetHigh := 0;
          ov.hEvent := CreateEvent(nil, TRUE, FALSE, nil);
       
          try
            hCancelEvent := CreateEvent(nil, TRUE, FALSE, nil);
       
            try
              // заполнение cb
              bRet := SetCommState(hPort, @cb);
              // запонение ct
              bRet := SetCommTimeouts(hPort, @ct);
       
              bRet := ReadFile(hPort, Pointer(@buf[0])^, BUFSIZE, dwBytesRead, @ov);
              // ...
       
              wo[0] := ov.hEvent;
              wo[1] := hCancelEvent;
              nRet := WaitForMultipleObjects(2, @wo[0], FALSE, DEADLOCK_TIMEOUT);
              if nRet = WAIT_OBJECT_0 + 0 then
              begin
                bRet := GetOverlappedResult(hPort, ov, dwBytesRead, FALSE);
                // ...
              end
              else if nRet = WAIT_OBJECT_0 + 1 then
              begin
                CancelIO(hPort);
              end;
              // ...
       
            finally
              CloseHandle(hCancelEvent);
            end;
       
          finally
            CloseHandle(ov.hEvent);
          end;
        finally
          CloseHandle(hPort);
        end;
      end;
    Сообщение отредактировано: Step -
      Цитата Step @
      Сам в Linux не силен от слова совсем, может кто подскажет как из этого лучше выкрутиться или ткнёт что почитать.

      Вероятно, можно принять, что некоторым аналогом WaitForMultipleObjects Виндус
      является select у Линукса.
      Можно почитать:
      1
      2
      3
        Ну да, примерно это же я всё уже читал. Ещё вычитал что select можно прервать путём отправки "сигнала", тогда он прервется и вернет EINTR.

        Размышляя пришел к такой формулеровке вопроса как "отмена блокировки", т.е. если ты используешь операцию которая блокирует выполнение на не определенный промежуток времени, то неплохо было бы иметь возможность её отменить. Для систем типа DOS в которых нет многозадачности это не имеет смысла, т.к. впринципе не существует другого процесса/потока который может затребовать отмену этой самой блокировки. Для многозадачных это становится актуальным. Под винду это как раз решается добавлением дополнительного Event'а, а вот под Linux ничего толкового не ищется - прерывать поток не рекомендуют, т.к. последствия теже что и винде - замусоривание. Единственное что более менее стабильное и безоспасное так это предложение крутить select с таймаутом в цикле, переодически прерываясь и проверяя что оно там вернуло. В таком случае таймаут имеет смысл ставить так чтобы попадать в итерации планировщика задач - меньше не имеет смысла, т.к. поток всё равно не будет выполняться два раза за цикл, а если будет, то это приведет к тому что он будет отбирать время у других задач.

        Ещё такой момент: под виндой у порта есть ReadIntervalTimeout, который я тоже использую, под Linux'ом я ничего такого не нашел и видимо придется городить огород, впринципе это сочетается с вариантом крутить select в цикле.
          Цитата Step @
          .. Под винду это как раз решается добавлением дополнительного Event'а, а вот под Linux ничего толкового не ищется - прерывать поток не рекомендуют, т.к. последствия теже что и винде - замусоривание. Единственное что более менее стабильное и безоспасное так это предложение крутить select с таймаутом в цикле, переодически прерываясь и проверяя что оно там вернуло. В таком случае таймаут имеет смысл ставить так чтобы попадать в итерации планировщика задач - меньше не имеет смысла, т.к. поток всё равно не будет выполняться два раза за цикл, а если будет, то это приведет к тому что он будет отбирать время у других задач.

          Да, я понимаю, такие же вопросы возникали и у меня.
          ---
          Не пробовал, но можно попробовать - в качестве дополнительного
          Event-а в Линукс использовать семафор.
          (как-то я эту потенциальную возможность упустил. Надо будет попробовать.)
          Если у тебя найдётся время и возможность - расскажи, что получилось.
          ---
          Если сработает T-OUT select-a это, конечно, затратит время.
          Но не так чтобы очень много.
          Бывает, что у Виндуса я это делаю (по разным причинам).
          Минус предложенного варианта даже не в затраченном времени,
          а в задержке реакции на событие. Об этом и в упомянутых статьях
          тоже не забыли написать.
          Сообщение отредактировано: ЫукпШ -
          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
          0 пользователей:


          Рейтинг@Mail.ru
          [ Script execution time: 0,0461 ]   [ 16 queries used ]   [ Generated: 18.04.24, 08:13 GMT ]