Event 와 CriticalSection 을 이용한 동기화 문제

kid1402의 이미지

8개의 스레드를 돌려 Queue 에 들어간 데이터를 처리하는 클래스가 있습니다.

즉 8개의 스레드 각각은 Queue를 Pop() 하여 데이터를 처리하고, 이때 CriticalSection을 이용하여 Queue에 대한 동기화 처리를 해줍니다. (8개의 스레드가 동시에 접근할 가능성이 있으므로)
쉽게 하기 위해 이 스레드를 PopThread라고 합니다.

다른 1개의 스레드는 같은 Queue에 처리할 데이터를 Push()합니다. 물론 이때도 Push()할 때에는 CriticalSection으로 Queue에 대한 동기화를 해줍니다. (위의 8개의 스레드가 동시에 접근하고자 하므로)
이 스레드는 PushThread 라고 합시다.

이때 이 Push()하는 스레드가 처리할 데이터를 Push()했음을 8개의 Pop() 스레드에게 알리기 위해, 즉 PushThread가 데이터를 Push() 했음을 PopThread에게 알리기 위해 Queue에 데이터를 Push() 한 뒤 SetEvent() 를 날려 이를 알립니다.
그리고 PopThread에서는 WaitForSingleObject() 로 PushThread에서 SetEvent 될 이벤트를 무한정 기다립니다.

그런데 여기서 문제가 생깁니다.

PushThread 에서 SetEvent를 할때

Sync( m_CS )
{
    m_DataQueue.push_back( Data ); 
}
SetEvent( m_ProcessDataEvent );

와 같이, 크리티컬 섹션 동기화는 오직 Queue에만 해주는 경우와 (논리적으로는 이게 맞죠. 크리티컬 섹션을 사용하는 목적 자체가 Queue에 대한 접근을 제어하기 위함이니까요)
(이 경우를 A 경우라고 합시다)

Sync( m_CS )
{
    m_DataQueue.push_back( Data );
    SetEvent( m_ProcessDataEvent );
}

와 같이 크리티컬 섹션 동기화를 SetEvent()에도 같이 해주는 경우가 있습니다.
다만 이 경우는 논리적으로 약간 말이 안될수도 있는게, 크리티컬 섹션은 Queue에 대한 동기화 처리를 위한 것이지, m_ProcessDataEvent에 대한 동기화 처리를 위한 것은 아니기 때문이죠.
또한 SetEvent는 ThreadSafe 하다고 알고 있습니다.
(이 경우를 B 경우라고 합시다)

제 생각으로는 이 두 경우 결과가 같아야합니다. 왜냐하면 SetEvent는 ThreadSafe 하기 때문에 크리티컬 섹션으로 동기화 처리를 해주던 말던 어차피 동기화가 되기 때문이죠.

그런데 실제 테스트에서는 이 두 경우가 다르게 나옵니다.

A의 경우, 논리적으로는 문제가 없음에도 불구하고 SetEvent() 되는 이벤트를 기다리는 8개의 스레드가 무한 루프에 빠집니다. WaitForSingleObject() 에서 기다리는 Event가 Set되지 않았음을 뜻하죠( 이 부분은 로그를 통해 확인해본 사항입니다)
반면 B의 경우는 논리적으로 생각하기에는 약간 말이 안되지만, 실제로는 잘 동작합니다. SetEvent도 제대로 동작하고 WaitForSingleObject()역시 무한루프에 빠지지 않습니다.

제 짧은 지식으로는 문제가 없어 보이는 두 경우가 왜 다르게 나오는 걸까요?
혹시 Critical Section과 Event 동기화를 동시에 사용하는 경우에 주의해야 하는 사항이라도 있는 걸까요?
Event를 이용하는데 있어서 제가 모르는 버그라도 있는걸까요? ( 작업환경은 VS.2005 입니다 )

저랑 비슷한 상황을 겪어보셨거나, 답을 알고 계신 분은 한마디 조언 부탁드립니다. ㅠㅠ

익명 사용자의 이미지

PopThread쪽 코드는 어떻게 되나요?

kid1402의 이미지

WaitForSingleObject( m_ProcessDataEvent, INFINITE ); // 대충 이런식으로 이벤트를 기다립니다

Sync( m_CS )
{
// 아래와 같이 크리티컬 섹션으로 큐에 대한 동기화를 해줘서 데이터를 처리합니다.
p_Data = m_DataQueue.front();
m_DataQueue.pop();

ProcessData( p_Data );
}

// 데이터 처리가 끝나면 이벤트를 reset 시켜줍니다
ResetEvent( m_ProcessDataEvent );

대충 이런 형태입니다

gilgil의 이미지

m_ProcessDataEvent 의 생성자에서 manualReset이 true인지 아니면 false인지 확인해 보세요.

그런데 push thread가 하나이고, pop thread가 여러개인가요?

kid1402의 이미지

m_ProcessEvent는 생성시에 CreateEvent( NULL, FALSE, FALSE, NULL) 로 기본인자가 주어지구요..

정확히는 pop thread( 즉 queue 데이터에 대한 worker thread) 가 8개이고, push thread는 따로 있는게 아니라 push 함수가 있어서 다른 스레드들이 해당 push함수를 호출하는 형식이라 딱 갯수가 정해진것이 아닙니다

kid1402의 이미지

bManualReset 값이 FALSE로 초기화 됬으니까 auto reset event를 생성하는게 되고..
그럼 ResetEvent가 안먹히게 된단 말씀이신가요?

autoReset이 됬기 때문에, push 쪽에서 SetEvent 하고 8개 쓰레드 중 하나가 WaitForSingleObject()로 이벤트를 받아오는 순간 자동으로 Reset되나요?

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.