[완료]Linux Thread, Semaphore를 이용한 Windows API WaitForMultipleObjects 질문
현재 Windows 어플을 Linux로 포팅하고 있습니다.
Windows 어플은 Server에서 넘겨주는 이벤트를 Client에서 Thread를 이용, WaitForMultipleObjects로 받고
어떤 이벤트가 발생했는지 구별하여 메세지를 Main함수에 있는 [Server 메세지 처리 함수]의 주소를 이용해 보
내고 화면에 보여줍니다.
[Server 메세지 처리함수]는 종료 조건이 있어 Server에서 넘겨온 메세지를 해석해 종료 조건이 발생 했을시 SetEvent를 이용, Thread를 종료하게 되어 있습니다.
이것을 Linux에서 pThread와 Semapore를 이용해 구현 해 보았습니다. 똑같이 pthread를 이용하고 Event를
Sepaphore로 처리 했습니다. 하지만 어떤 이벤트가 발생했는지 알 수 없어 Server에서 메세지를 무조건 받아서
Main함수의 [Server 메세지 처리 함수]의 주소를 이용해 보내 화면에 출력했습니다.
결과는 10회 반복했을때 1회는 무조건 성공합니다. 하지만 그 다음 2~3회부터 문제가 발생합니다.
Server 메세지 72개중에 7개를 유실해 버리거나 이상한 메세지를 받거나 메세지를 받지 못한다고 오류를 발생
시킵니다. 쓰레드를 이용하지 않고 [Server 메세지 처리 함수]를 소스에 포함시켜 하나로 동작시키면 10회 반복
시 전부 제대로된 값을 잘 받아 보여줍니다. 때문에 WaitForMultipleObjects를 신경쓰지 않고 Server메세지
를 무조건 받아서 화면에 보여주게끔 만들었던 것입니다. 쓰레드 이용할때에만 저런 에러를 발생시킵니다.
참고로 Server에서 넘겨오는 메세지는 Windows에서 File mapping을 이용해 처리하지만 Linux에서는 오로지 Malloc으로 처리하게끔 만들었습니다.
Sync쪽에 문제가 있는것 같은데 아무리 생각해 봐도 잘 모르겠습니다. 위에서 말한 것과 같이 프로그램을 10회
반복시 어쩔때는 2~3회 잘 받고 혹은 5회까지 잘 받아올 때도 있습니다. 간혹 10번다 잘 돌아갈때도 있습니다.
어떤 쪽에 문제가 있는지 고수님들 도움 부탁드립니다.
세마포어와
세마포어와 WaitForMultipleObjects는 개념이 다릅니다...
세마포어는 특정 개수의 자원을 공유해서 쓰라는건데요...WaitForMultipleObjects는 좀 더 확장된 개념입니다. 즉, 세마포어에서 초기에 5개의 자원을 입력하면, 세마포어 객체는 카운터만 정확히 셉니다 (경쟁상태에서요) 덕택에 음수값도 가질수 있지요. (5,4,3,2,1,0,-1,-2...) 음수값을 가지게되면 미리 자원을 소유하던 녀석들이 자원해제시에 하나씩 +1 되면서 종국에는 초기값인 5로 돌아가게 됩니다.
반면...WaitForMultipleObjects는 함수명 그대로...여러개의 핸들이 자원해제되기를 기다립니다. (보통은 저 옵션으로 많이 쓰지요...간혹 여러개중 단 하나의 핸들이라도 자원해제되면 blocking이 풀리지만)
함수의 용도 자체가 좀 다릅니다 ^^
------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/
아~ 그런데..
세마포어의 개념이 Windows의 Event의 역할도 합니다.
즉, sem_wait함수로 대기 시켰다가 sem_post함수로 재가동 시키면 됩니다.
다시 정리하면
WaitForSingleObject(),WaitForMultipleObjects()를 sem_wait()로 바꾸고
setEvent()를 sem_post()로 바꾸면 완벽하지는 않지만 그럭저럭 Event효과를 낼 수 있습니다.
그리고 WaitForMultipleObject()에서 Event구분은 flag변수를 써서 구분하는것도
가능하다고 생각합니다.
이벤트를 보냄과
이벤트를 보냄과 동시에 그 이벤트에 연관된 메시지를 공유 메모리를 통해 전달하려는 것 같은데 맞나요? 그리고 혹시 그 공유 메모리는 queue구조가 아니라 단 하나의 메시지만을 저장하게 되어 있나요? 만약 그렇다면, 서버에서 1st, 2nd, 3rd 이벤트를 순식간에 fire하고, 그 와중에 클라이언트에서 느릿느릿 1st 이벤트를 처리하다가는 자칫 공유 메모리에는 1st 이벤트에 대한 메시지가 아니라 2nd나 3rd 이벤트에 대한 메시지가 들어있는 상황이 생길 수 있을 것 같은데요. (혹은 쓰다만 깨진 데이터일 수도...)
그래서..
totohero님께서 말씀하신대로 그런 상황이 발생할거 같아서 아예 서버 메세지 자체를 한 글자씩(16비트) 받아오는 것으로 구현 하였습니다. 서버메세지를 한글자씩 받아와 공유메모리에 넣고, 서버 메시지는 후에 구조체 형식으로 바뀌어 메인 함수에 전달됩니다. 쓰레드를 사용하니 서버에서 메세지 받아오는 것은 문제가 되지 않는데 다만 시간이 좀 걸리네요. setpriority함수를 사용해 쓰레드 CPU점유을 올려보아도 체감상 그리 나아지진 않았습니다.
정말 제가 말했던
정말 제가 말했던 상황이라면 race condition이 있다는 말인데, 쓰신 내용은 단지 timing을 조절하신 건가요? 메시지를 queue로 전달한다든지 하는 구조적인 변경이 필요하다고 보는데요.
그 점은
그 점은 이미 쓰레드가 서버 메세지를 받기 위해 미리 생성되고 동작하고 있습니다. 즉, 메인이 호출 한 함수에서 서버에게 동작 상태를 넘겨 달라는 메세지를 보내기 전 이미 쓰레드는 생성 동작 하고 있습니다. 다만 서버 메세지 이벤트가 언제 오느냐가 문제 입니다. Windows는 WaitForMutipleObjects 함수로 서버 이벤트가 오는걸 그때그때 확인하고 처리 할 수 있지만 Linux에서는 모두 수동으로 해줘야 하기 때문에 문제가 발생합니다. 때문에 쓰레드를 생성하고 sem_wait함수로 대기 시켜놓은 상태에서 메인함수가 호출한 함수가 서버에게 동작 상태를 넘겨 달라는 메세지를 보냄과 동시에 sem_post함수를 호출시켜 쓰레드가 미리 서버 메세지가 들어오기 전 recv함수로 기다립니다. 이런 비동기적 구조이기 때문에 race condition 상황이 발생하지 않습니다.
해결 했습니다.
결국은 쓰레드에 문제가 있었네요. 쓰레드를 강제로 죽이고 돌리니 잘 돌아갑니다. 그래도 먼가 좀 허전하네요.
댓글 달기