2010-03-03 4 views
1

2 스레드와 글로벌 큐, 하나의 스레드 (t1) 데이터를 밀어 넣고 또 다른 하나 (t2)가 데이터를 팝합니다. Windows API를 사용하여 중요한 섹션이있는 큐를 사용할 수있는 함수를 사용하지 않고이 작업을 동기화하고 싶습니다.중요 섹션을 사용하는 대신 대기열 변수 주소를 잠그는 방법?

대기열은 글로벌이며 동기화 방법을 알고 싶습니다. 대기열의 주소를 잠그면됩니까?

답변을 많이 주시면 감사하겠습니다. :)

위의 문제에 부스트 라이브러리를 사용할 수 있습니까?

는 당신에게 감사

+0

왜 crit 섹션을 원하지 않는 구체적인 이유가 있습니까? 그것의 가장 빠른 afaik. – vpram86

+0

다른 스레드가 팝하기 전에 대기 할 수 있도록 주소를 잠그고 싶습니다. 임계 구역을 사용하여 어떤 문제가 발생 했으므로 변수 자체를 잠그기로 결정했습니다. :) – mahesh

+0

아마도 중요한 섹션을 사용하여 큐를 수정하는 방법에 대해 물어 보는 것이 좋습니다.잠금없는 큐는 가능하지만 확실한 잠금없는 코드는 잠금을 사용하는 올바른 코드보다 쓰기가 훨씬 어렵습니다. –

답변

3

한 가지 방법은 대기열에 하나 개의 더미 항목을 항상함으로써이 문제를 극복 할 수있다 두 개의 큐 대신 중 하나를 가지고 :

  • 생산자 스레드 A를 큐에 항목을 밀어
  • 소비자 스레드가 항목을 팝업하고자 할 때, 큐 A는 빈 대기열 B.와 교체되어
  • 생산자 스레드는 항목을 새로운 대기열 A로 밀어 넣음을 계속합니다.
  • 소비자는 중단되지 않고 대기열 B에서 항목을 소비하고 비워냅니다.
  • 큐 A는 정말 두 개의 포인터를 교환의 문제 때문에 고속 동작되어야 큐 B 등

큐가 교환 될 때 유일한 로크/차단/동기화가 일어나는과 교환된다.

0
난 당신이 어떤 아토 또는 전혀 스레드 안전한 재료를 사용하지 않고 그 조건 큐를 만들 수 있다고 생각

?

은 서클 버퍼가 단 하나이면 스레드가 읽기 포인터를 제어하고 다른 스레드는 쓰기 포인터를 제어하는 ​​것과 같습니다. 모두 읽기 또는 쓰기가 끝날 때까지 업데이트되지 않습니다. 그리고 그냥 작동합니까? 어려움의

유일한 점은 큐가 꽉 찼거나 비어 있는지 쓰기 == 읽을 때 결정되어 있지만, 당신은 단지

class Queue 
{ 
    volatile Object* buffer; 
    int size; 
    volatile int readpoint; 
    volatile int writepoint; 

    void Init(int s) 
    { 
      size = s; 
      buffer = new Object[s]; 
      readpoint = 0; 
      writepoint = 1; 
    } 

    //thread A will call this 
    bool Push(Object p) 
    { 
     if(writepoint == readpoint) 
     return false; 
     int wp = writepoint - 1; 
     if(wp<0) 
      wp+=size; 
     buffer[wp] = p; 
     int newWritepoint = writepoint + 1; 
     if(newWritepoint==size) 
      newWritePoint = 0; 
     writepoint = newWritepoint; 
     return true; 
     } 

     // thread B will call this 
     bool Pop(Object* p) 
     { 
      writepointTest = writepoint; 
      if(writepointTest<readpoint) 
       writepointTest+=size; 
      if(readpoint+1 == writepoint) 
       return false; 
      *p = buffer[readpoint]; 

     int newReadpoint = readpoint + 1; 
     if(newReadpoint==size) 
      newReadPoint = 0; 
     readpoint = newReadPoint; 
     return true; 
     } 
}; 
+0

잠금없는 큐를 작성할 수는 있지만 사소한 것은 아닙니다. 한 예를 보려면 http://www.drdobbs.com/cpp/210604448을 참조하십시오. –

+0

@Jerry 예 잠금 대기열을 공동 작성했지만 여전히 잠금 기능을 사용하고 있습니다. 위의 코드는 작동하지 않아야한다. 위의 코드가 원하는대로 작동한다면 더 일반적으로 스레드로부터 안전 할 수있는 적절한 잠금 대기열을 작성해야하는 이유는 없습니다. 나는 위의 코드가 == 실패하는지 알기를 원할 것이다. – matt

+0

작동 할 수있는 조건이있을 수 있지만 명시된 제약 조건 (명시된 것 이상)이 필요합니다. 예를 들어 int를 암묵적으로 읽고 쓰는 것을 요구하는 것 같습니다. Pop()이 writepoint와 동시에 writepoint를 읽었을 때 읽기/쓰기가 원 자성이 아니라면 심각한 문제가 될 수 있습니다. –

0

이 문제를 처리하는 또 다른 방법은 큐를 동적으로 할당하고 포인터에 할당하는 것입니다. 항목을 대기열에서 제외해야하는 경우 포인터 값이 스레드간에 전달되고 중요한 섹션으로이 작업을 보호합니다. 이는 모든 푸시에 대해 대기열에 잠그는 것을 의미하지만 항목 제거에 대한 경합은 훨씬 적습니다.

이 기능은 대기열에 넣기와 대기열에서 대기열에 넣기 사이에 항목이 많을 때 잘 작동하며 몇 가지 항목이 적을 때 잘 처리되지 않습니다.

예 (잠금을 수행하려면 일부 RAII 잠금 클래스를 사용하고 있습니다.) 또한 참고 ... 오직 한 스레드가 dequeueing 때 정말 안전합니다.

queue* my_queue = 0; 
queue* pDequeue = 0; 
critical_section section; 

void enqueue(stuff& item) 
{ 
    locker lock(section); 
    if (!my_queue) 
    { 
     my_queue = new queue; 
    } 
    my_queue->add(item); 
} 

item* dequeue() 
{ 
    if (!pDequeue) 
    { //handoff for dequeue work 
     locker lock(section); 
     pDequeue = my_queue; 
     my_queue = 0; 
    } 
    if (pDequeue) 
    { 
     item* pItem = pDequeue->pop(); //remove item and return it. 
     if (!pItem) 
     { 
     delete pDequeue; 
     pDequeue = 0; 
     } 
     return pItem; 
    } 
    return 0; 
} 
관련 문제