2009-11-25 8 views
0

QGraphics * 클래스가 스레드로부터 안전하지 않다고 생각합니까? 나는 오래된 애플 리케이션을 Qt에 포팅하고 있으며, 다중 스레드로 만들려고 시도하고있다. 나는 업데이트 코드를 보았고 아무런 잠금이없는 것을 본다.QGraphicsView/Scene - 멀티 스레드 악몽

필자가 시작한 모든 작업은 GUI가 차단할 필요가 없도록 일련의 작업자 스레드로 수행됩니다. 그러나 시각적 표현을 표시하자마자 업데이트 코드가 다른 스레드가 쓰고있는 버퍼에서 읽으려고 시도 할 때 모든 것이 한 묶음의 카드처럼 떨어집니다.

  1. 는 타원의 무리
  2. 이 장면에서 모든 개체에 어떤 설정을 수정 스레드를 만들고 루프에서 그것을 장면 포인터
  3. 을 통과 개체 만들기 :

    여기 내 테스트 케이스이다.

테스트 기능 : 나는이 문제를 해결할 수있는 방법에 대해 생각되었다

bool CBasicDocument::Update(float fTimeStep) 
{ 
const QList<QGraphicsItem*> tObjects = items(); 

for(QList<QGraphicsItem*>::const_iterator tIter = tObjects.constBegin(); 
tIter != tObjects.constEnd(); 
++tIter) 
{ 
    QGraphicsEllipseItem* pElipse = (QGraphicsEllipseItem*)(*tIter); 
    if(pElipse) 
    { 
     pElipse->setPen(QPen(QColor((int)(255.0f * sinf(fTimeStep)), (int)(255.0f * cosf(fTimeStep)), (int)(255.0f * sinf(fTimeStep))))); 
    } 
} 
return true; 
} 

그리고 그들 중 누구도 특히 꽤 있습니다.

내가 원하는 것은 이상적으로 다음 렌더링 호출까지 버퍼링되는 객체의 설정을 변경하는 것이지만, 당분간은 충돌하지 않고 해결할 것입니다.

  1. 더블 록 스텝 두 장면 그래프 (한 렌더링 한 업데이트)를 유지하는 전체 장면을 버퍼 : 순간

    나는 네 가지 옵션이 있습니다. 이것이 멀티 스레드 게임 엔진의 작동 방식입니다. 이것은 CPU 시간을 두 배로 늘리고 메모리를 두 배로 늘리므로 끔찍한 일입니다. 두 장면 그래프를 유지 관리하는 데 필요한 물류는 말할 것도 없습니다.

  2. 위와 같이 QGraphics *를 스레드로부터 안전하게 수정하십시오. 이것은 아마도 가장 실용적인 접근 방법 일 것입니다. 그러나 그것을 끝내기 위해서는 많은 노력이 필요합니다.

  3. 장면을 대기열로 밀어 넣고 주 스레드에서 처리합니다.

  4. 당분간 바람에 멀티 쓰레딩을 던져서 문서가 업데이트 될 때 내 앱이 멈추게하십시오. (일부 문서의 경우 데이터 크기가 충분하지 않음)

특히 매력적이며 많은 작업이 필요합니다.

아무도 아이디어를 가지고 있지 않거나 QGraphicsScene을 멀티 스레딩하기 전에 시도한 적이 있습니까?

건배

답변

2

난 항상 상관없이 당신이 다른 GTK 또는 Qt를 사용하지 않는 것, 그것은 모든 GUI 작업은 메인 스레드에서 발생 가지고 더 나은 생각 읽었습니다.

귀하의 경우 2 번 옵션으로 갈 것입니다.

Qt의 코드를 수정하여 여기에 잠금을 설정하면 수정 된 Qt를 중요한 작업없이 업스트림과 동기화 할 수 없기 때문에 ihmo를 수행하는 것이 최악입니다.

+0

아쉽게도 구성 요소를 설정하는 데 상당한 시간이 걸릴 수 있습니다 (단, 해당 단계로 이동하는 데 필요한 처리 시간은 아님). 렌더링 된 문서의 특성을 감안할 때 나는 QGraphicsScene을 데이터로, QGraphicsView를 GUI로 취급하고 있습니다. 바르게 지적했듯이, 변경 사항을 메인 Qt 브랜치와 병합하는 것이 주요한 악몽 일 것입니다. 또한, 업데이트 코드에는 잠금 장치를 넣는 것이 중요하지 않은 많은 입구가 있습니다. – icStatic

0

테스트 기능에서 QGraphicsItem을 QGraphicsEllipseItem에 이미 캐스팅 (C 스타일 캐스트를 사용)했음을 알 수 있습니다. 특정 유형의 항목 유형 만 사용하는 경우 해당 유형을 서브 클래스 화하고 해당 서브 클래스에서 스레드 안전 기능을 제공하는 것이 더 쉽습니다. 그런 다음 해당 하위 클래스로 캐스트 한 다음 다른 스레드에서 원하는 것을 호출하십시오. 변경 사항 버퍼링이나 뮤텍스 잠금 또는 이러한 변경 사항에 대해 수행하려는 작업을 처리 할 수 ​​있습니다.

대안은 하나의 뮤텍스를 갖고, 처리 할 때 각 스레드가이를 잠그는 것입니다. 뮤텍스가 사용 가능해질 때까지 기다릴 때마다 속도가 느려질 수 있습니다. 또한 두 스레드가 도달 할 수있는 items-> mutexes 맵을 유지 관리 할 수 ​​있으며 각 스레드는 작업 할 때 작업중인 항목에 대한 뮤텍스를 잠급니다. 서브 클래 싱 옵션이 너무 복잡하다고 생각하면 레이어를 추가하는 것이 더 간단 할 것입니다.

+0

아주 기본적인 예제이므로 고의적 인 내용입니다. 실제로 나는 더 안전한 방법으로 더 현명한 서브 클래스에 적절한 캐스팅을 수행 할 것입니다. 뮤텍스의 문제는 메인 스레드에서 뮤텍스를 잠글 수 있어야한다는 것입니다. 안타깝게도 QGraphicsView 객체 내부의 이벤트 내부에서 객체에 액세스하며 데이터를 설정하는 접근 자 함수는 가상이 아닙니다. QGraphicsView에서 이벤트 핸들러에 과부하를 걸고 거기에 전역 잠금을 설정할 수 있는지 궁금합니다. 실제로 죽어 가고있는 비트는 QMetaCallEvent에서 q_updateLaterSlot을 호출 한 것입니다. – icStatic

+0

해당 하위 클래스를 통해 하위 클래스에 액세스하고 개체에 액세스 할 수있는 경우 이벤트를 통해 실제 데이터 변경 내용을 모두 보낼 수 있습니다. 즉, 작업자 스레드는 객체 A에게 foo를 변경하라고 지시하고 객체 A는 "ChangeFoo"이벤트를 만들고이를 자체에 게시하고 customEvent는 ChangeFoo 이벤트를 처리하여 실제로 foo를 새 설정으로 변경합니다. 그런 식으로 데이터 변경은 UI 스레드에서 발생합니다. 컨트롤러가 변경 사항을 지시하는 경우에도 다른 스레드에 있습니다. –

+0

아마도 이것이 아마도 가장 좋은 아이디어라고 생각합니다. 감사합니다 :) 나는 조사 할 것이다. 나는 또한 Trolltech 사람들 중 한 명을 잡아서 그들이 말하는 것을 보게 될 것이라고 생각합니다. – icStatic