입출력 여러개, select함수, timeout에 대해서 질문입니다.

kingchobo의 이미지

갑자기 머리가 복잡해져서 여쭙니다.

select함수를 사용해서 입출력장치 여러개를 제어합니다.
그리고
각각의 장치는 마스터쪽에서 보내는 명령어에 대해
어느 일정 시간 내에 대답을 해야 합니다.

예를 들어 1초안에 대답안하면 전송오류로 생각하는 제어모듈이 장치 3개를 제어하고 있습니다.

이럴경우 select함수내의 timeout값을 1초로 해서 이용한다면
첫번째 fd에서 1초 기다리고, 그 다음 fd에서 1초, 다음 fd에서 1초
이렇게 기다리게 되는 거잖아요?
결국엔 마지막 fd는 3초를 기다리게 되는거 아니겠나요?

이는 실시간성이 전혀 보장 되지 않지 않습니까?

저런 장치 제어 모듈을 구현하기 위해
select나 epoll을 사용한다는건 애당초 안되는 건가요?
아니면 select내의 timeout값을 이용하는 것은 여러개의 장치일때는 의미가 없는건가요?
다른방식의 시간 check가 필요한가요?

고수분들의 고견 부탁드립니다.

IsExist의 이미지

select는 stream-based fd 에만 유용한걸로 알고 있고요.

timeout은 그런 의미가 아니라 전체 1초 동안에 셋중에 어떤 event가 발생하지
않으면 timeout이 됩니다.

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

kingchobo의 이미지

아. 그런거였군요. 얇팍한 지식. 으. :oops:

그럼 동시에 타임아웃내의 시간동안 event가 동시에 두개 발생하면 어떻게
되는 건가요?

그럼 또 복잡해지는데?

cjh의 이미지

kingchobo wrote:
아. 그런거였군요. 얇팍한 지식. 으. :oops:

그럼 동시에 타임아웃내의 시간동안 event가 동시에 두개 발생하면 어떻게
되는 건가요?

그럼 또 복잡해지는데?

그러면 select() 반환시 두개 이상의 fd가 세트되므로 FD_ISSET으로 확인하면 되겠지요.

--
익스펙토 페트로눔

서지훈의 이미지

cjh wrote:
kingchobo wrote:
아. 그런거였군요. 얇팍한 지식. 으. :oops:

그럼 동시에 타임아웃내의 시간동안 event가 동시에 두개 발생하면 어떻게
되는 건가요?

그럼 또 복잡해지는데?

그러면 select() 반환시 두개 이상의 fd가 세트되므로 FD_ISSET으로 확인하면 되겠지요.


근데 select()는 이벤트가 발생하면 실행이 될텐데 2, 3개의 이벤트 발생은 무시되어야 하지 않나요?
물론 FD_ISSET()은 하나의 정상적인 경우에도 사용을 해야 하는 거구요.
FD_ISSET()없으면 select()는 사용 못합니다.
sleep()대용으로나 쓸까나.

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

ssehoony의 이미지

select 가 block 된 상태에서 이벤트가 들어오면 그땐 반환 되는게 1개가 맞습니다.
하지만, 다른 작업을 하고 있는 도중에 이벤트가 여러개 발생해서 대기중일대 select 함수를 call 하면 그때까지 처리되지 않은 이벤트 모두가 반환됩니다.
그때 select 의 리턴값으로 몇개의 이벤트가 반환됐는지 알 수 있습니다.
select man 페이지는 자세히 읽어보시면 도움이 될 듯 하군요.

서지훈의 이미지

근데... 어짜피 FD_ISSET()은 loop문을 이용해서 다 검사하지 않나요?

앞서 한 얘기는 동시에 select() 하부의 코드가 실행 중일 때는 무시 되어야 하는게 아닌가 하는 그런 문맥의 흐름인데...
저도 약간 착각한 부분이 있을 지도.

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

ssehoony의 이미지

kingchobo wrote:
아. 그런거였군요. 얇팍한 지식. 으. :oops:

그럼 동시에 타임아웃내의 시간동안 event가 동시에 두개 발생하면 어떻게
되는 건가요?

그럼 또 복잡해지는데?

이 글을 보니 select 가 timeout 시간까지 무조건 기다렸다가
그 시간 사이에 발생한 모든 이벤트를 알려주는 것으로 오해하신것 같은데, select 는 이벤트가 발생하면 즉시 반환해 주며, 다만 timeout 시간이 지나도 이벤트가 발생하지 않을시에 timeout이 됐다는 리턴값을 반환할 뿐입니다.

그러므로 3개에 대한 각각 1초내 응답이 됐는지를 알기 위해서는 select 만으로 해결이 불가능합니다. 3개 각각에 대해 요청 시각을 기록한 후 그 시간과 현재 시각을 비교해서 요청에대한 응답이 timeout 이 됐는지 확인하셔야 합니다.

bugiii의 이미지

각각의 fd 에 따로 따로 timeout 을 적용시키려면 ssehoony 님의 말씀처럼 요구에 맞게 구현을 더 해야 합니다.

이런 걸 좀 편하게 해주는 라이브러리도 있습니다. libevent 라는 것인데요. 개별 timeout 도 적용되고 콜백 호출을 해주는 형태이면서 select, poll, epoll, kqueue 등을 감싸주는 API 를 제공해줘서 잘 사용하고 있습니다.

kingchobo의 이미지

Quote:
이 글을 보니 select 가 timeout 시간까지 무조건 기다렸다가
그 시간 사이에 발생한 모든 이벤트를 알려주는 것으로 오해하신것 같은데, select 는 이벤트가 발생하면 즉시 반환해 주며, 다만 timeout 시간이 지나도 이벤트가 발생하지 않을시에 timeout이 됐다는 리턴값을 반환할 뿐입니다.

그러므로 3개에 대한 각각 1초내 응답이 됐는지를 알기 위해서는 select 만으로 해결이 불가능합니다. 3개 각각에 대해 요청 시각을 기록한 후 그 시간과 현재 시각을 비교해서 요청에대한 응답이 timeout 이 됐는지 확인하셔야 합니다.

그렇다면 3개의 이벤트가 순차적으로 발생했을때. 1번 이벤트 2번 이벤트 3번 이벤트라 칭하고
1번 이벤트가 먼저 발생했다하고, select를 빠져 나와서 그 이벤트를 처리하는동안(이 시간이 좀 길다 치면요.) 2번 3번 이벤트가 들어왔다면 어떻게 되는 거지요? 2번 3번 이벤트는 무시되나요?

ssehoony의 이미지

ssehoony wrote:
select 가 block 된 상태에서 이벤트가 들어오면 그땐 반환 되는게 1개가 맞습니다.
하지만, 다른 작업을 하고 있는 도중에 이벤트가 여러개 발생해서 대기중일대 select 함수를 call 하면 그때까지 처리되지 않은 이벤트 모두가 반환됩니다.
그때 select 의 리턴값으로 몇개의 이벤트가 반환됐는지 알 수 있습니다.
select man 페이지는 자세히 읽어보시면 도움이 될 듯 하군요.

음.. 여기 답변이 있는데 ^^;;

kingchobo의 이미지

select가 블록된상태라는 말의 의미가 무엇인지요?
이벤트 발생을 대기하는 기간 상태를 말씀하시는 건가요?
그렇다면 타임아웃을 0으로 했을때는 어떤 fd에 이벤트가 발생했는지만 체크하고 넘어가는 건가요?

음 그리구.
만일 블록이라는 의미가 그거라면
시나리오를 한번 생각하면
일단
1. select가 블록 되어 있다.
2. 1번 이벤트 발생
3. select는 이벤트 1개를 반환하면서~ 리턴
4. 해당 루틴 수행 (좀 길게)
5. 4번 루틴 수행동안 2번, 3번 이벤트 발생~
6. 2번, 3번 이벤트는 대기
7. 다음 select 수행시 2번, 3번에 대한 이벤트를 리턴

이런 시나리오인가요?

또. 제가 본 man페이지는 이렇습니다.
그런얘기 안나와염.. ㅜ.ㅜ

Quote:
SELECT(2) 리눅스 프로그래머 매뉴얼 SELECT(2)

이름
select, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - 동기적 I/O 다중화

사용법
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);

FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);

설명
select 는 상태가 변경되는 파일 기술자들의 숫자를 기다린다.

세개의 독립적인 파일 기술자 집합들을 검사한다. readfds 에 리스트된 것
들 은 문자들을 읽어들일수 있는가가 검사되며(더 정확히는, 읽기가봉쇄되지
않았는지를 검사하기 위해서이다 - 특별히, 파일 기술자 또 한 end-of-file
일 수도 있다.), writefds 에 있는 것들은 쓰기가 봉쇄되지 않았는가가 검사
되며 exceptfds 에 있는 것들은 예외가 있는지가 검사된다. 종료시, 이 집
합 들 은 파일 기술자들이 실제로 변경된 상태가 무엇인지 가리키도록수정된
다.

네개의 매크로가 이 집합들을 제어하기 위해 사용된다. FD_ZERO 는 집합 을
소 거한다. FD_SET 와 FD_CLR 는 집합에서 주어진 기술자를 더하거나 뺀다.
FD_ISSET 는 기술자가 집합의 일부분인지 아닌지를 검사 한 다.: 이 것 은
select 가 반환된후 유용하다.

n 은 세개의 집합중 가장 높은 파일기술자에다가 1을 더한다.

timeout 은 select 가 반환하기 전에 경과해야 하는 시간의 상위 제한 값이
다. 0으로 지정되면 select 는 즉시 반환된다. 만일 timeout 이 NULL 이
면(timeout이 없을경우), select 는 무한히 봉쇄될수 있다.

반환값
성공시, select 는 파일 기술자 집합에 포함된 기술자들의 숫자를 반환하며,
어떠한 일이일어나기 전에 타임아웃이 발생하면 0을 반환한다. 에러시, -1
이 반환되며, errno 는 적당한 값으로 설정된다.; 집합들과 timeout 은 정의
가 안되며, 그래서 에러후 이것들의 내용에 의지할수 없다.

에러
EBADF 유효하지 않은 파일 기술자가 집합중 하나에 들어 있다.

EINTR 비-블럭된 신호가 잡혔다.

EINVAL n 이 음수이다.

ENOMEM select 가 내부 테이블들을 위한 메모리를 할당할수 없다.
주의
몇몇 코드들은 정확성을 가지고 잠복시키기 위해 꽤 호환되는 방법으로써 세
개 의 집합을 비우고, n 은 0, 그리고 timeout 은 null이 아니게 설정하여
select 를 호출한다.

리눅스에서, timeout 은 잠복되지 않은 시간의 양을 반영하기 위해 수 정 된
다; 대부분의 다른 수행들은이렇게 되지 않는다. 이것은 timeout 을 읽은 리
눅스 코드들이 다른 OS로 포팅되거나 코드들이 초기화를 다시 하지않고 반복
문 에서 다중 selects 를 위해 timeval 구조체를 다시 사용하여 리눅스로 포
팅할때 문제들을 야기한다. select 에서 반환된후 정의되지 않 은 timeout
을 고려해야 한다.

예제
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;

/* 입력된때를 알아보기 위해 stdin (fd 0)을 검사한다. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* 5초를 기다린다. */
tv.tv_sec = 5;
tv.tv_usec = 0;

retval = select(1, &rfds, NULL, NULL, &tv);
/* 지금 tv 값에 의존하지 마라. */

if (retval)
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) 는 true이다. */
else
printf("No data within five seconds.\n");

exit(0);
}

호환
4.4BSD ( select 함수는 4.2BSD에서 처음 나타났다.). 일반적으로 BSD 소켓
층(System V 변종들을포함하여)의 복사판들을 지원하는 non-BSD계열과 호 환
된다. 그러나, System V 변종들은 전형적으로 종료전에 timeout 변수를 설
정하지만, BSD 변종들은 그렇게 하지 않는다는것을 주의해라.

관련 항목
accept(2), connect(2), poll(2), read(2), recv(2), send(2), write(2)

ssehoony의 이미지

kingchobo wrote:
select가 블록된상태라는 말의 의미가 무엇인지요?
이벤트 발생을 대기하는 기간 상태를 말씀하시는 건가요?
그렇다면 타임아웃을 0으로 했을때는 어떤 fd에 이벤트가 발생했는지만 체크하고 넘어가는 건가요?

음 그리구.
만일 블록이라는 의미가 그거라면
시나리오를 한번 생각하면
일단
1. select가 블록 되어 있다.
2. 1번 이벤트 발생
3. select는 이벤트 1개를 반환하면서~ 리턴
4. 해당 루틴 수행 (좀 길게)
5. 4번 루틴 수행동안 2번, 3번 이벤트 발생~
6. 2번, 3번 이벤트는 대기
7. 다음 select 수행시 2번, 3번에 대한 이벤트를 리턴

이런 시나리오인가요?

네. 위에 말씀하신 대로 작동합니다.
여기에 조금 더 시나리오를 추가 하면
8. select 블록 (timeout 을 5초로 셋팅)
9. 5초동안 이벤트 발생하지 않음
10. select 가 0을 리턴
11. 잠시 다른 일
12. select 블록 (timeout을 0으로)
13. 미처리이벤트가 없으므로 select 는 즉시 0 반환
14. 잠시 다른 일
15. 14번을 하는 도중 이벤트 2개 발생
16. select 블록 (timeout 을 0으로)
17. 15번에서 발생한 이벤트 2개 반환

이정도가 익숙해 지시면
read 이벤트와 write 이벤트에 대한 구분도 필요하겠군요.
소켓 통신시에는 write 이벤트에 대해서도 꼭 알아두셔야 합니다.

익명 사용자의 이미지

18. 타임아웃 포인터를 NULL(무한대기), 또는 타임아웃의 시간> 0인 상태
19.  IO 이벤트 발생 (select에서 탈출, return값 > 0 )
20. 19에서 발생한 이벤트 처리
21. 18처럼 select에서 대기중
22. 임의의 시그널( CTRL+C, 알람, 차일드, 타이머, 파이프....등등)이 발생
23. IO 이벤트는 아니지만, select에서 탈출, return값 = -1, errno번호참고

select() 호출하면?
1. 기본적으로 block됨
2. 그렇다면, 탈출(리턴)해야 하는데...언제 탈출하나?
2-1 select()호출시 입력 파라메터 값이 잘못됨
2-2 한개 이상의 이벤트(In,Out, Exception) 발생
2-3 지정한 시간이 초과(타임아웃)
- 이 시간을 tv_sec =0, tv_usec=0으로 하여 마치 non-block인것처럼 간주할 수 있으나, 정확히는 타임아웃이다.
2-4 타임아웃 또는 이벤트를 대기중인데, 시그널이 발생

* 위에서 다른 분들이 좋은 의견 많이 있었습니다.
* 질문자 님의 경우, 매 장비별 별도 타이머( 또는 타임관리 루틴)가 필요하리라 예상되며,
멀티쓰레드를 이용하거나 멀티프로세스로 코딩하시는 것이 더 좋은 선택으로 보입니다.
* bugiii님이 추천하신, select(), poll()등 일반적인 *NiX 시스템의 IO이벤트 처리루틴과, 특정 시스템에 제한되는 특성을 가진 epoll, kqueue, /dev/poll등을 잘~ wrapping한 libevent()를 사용하시는 것도 좋습니다.
* 좋은 프로그램 많이 만드세요.

익명 사용자의 이미지

코드로 보면 대략
ret=select(...);
if (ret > 0 ) {...} // 이벤트 발생(IO, exception)
else if ( ret < 0 ) {...} // 에러나 시그널
else {...} // ret == 0 , 타임아웃

이래야 한다는....

kingchobo의 이미지

Quote:
* 질문자 님의 경우, 매 장비별 별도 타이머( 또는 타임관리 루틴)가 필요하리라 예상되며,
멀티쓰레드를 이용하거나 멀티프로세스로 코딩하시는 것이 더 좋은 선택으로 보입니다.

그랬던 것인가요?
음 멀티 쓰레드가 필요했던거군요.

어디 그렇게 구현된
샘플예제 없나요?

익명 사용자의 이미지

모 어렵게 생각하지 마시고, 장비 하나에 대해 처리하는 것을 함수 수준으로 작성하신 다음 즉, 1개에 대해서 잘 만드시고요.
이를 쓰레드(프로세스)로 다수개 생성하시고, 쓰레드라면 쓰레드들의 상태정보를 글로벌 변수로 놓고, 프로세스라면 공유메모리등 IPC메카니즘으로 동기화하여
이를 모니터링하는 쓰레드(프로세스) 하나 더 만드시면 되겠습니다.

* 쓰고보니, 말만 쉽군요. 전형적인 서버프로그램 유형으로 시작해보세요.
서버유형은 스티븐스님의 UNP시리지에 많이 있겠군요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.