2009-04-07 10 views
1

그래픽 용 SDL과 스레드 용 pthread를 사용하여 C++에서 간단한 광선 추적 프로그램을 만들고 있습니다. 그리고 두 개의 코어를 사용하여 프로그램을 만드는 데 문제가 있습니다. 스레드는 작동하지만 두 코어를 100 %로 구동하지 않습니다. SDL 인터페이스를 사용하기 위해 SDL_Surface.pixels 메모리에 직접 씁니다. 따라서 SDL 잠금을 사용할 수 없다고 가정합니다.다중 코어를 사용하기 위해 pthread를 사용할 때의 문제

void* renderLines(void* pArg){ 
while(true){ 
    //Synchronize 
    pthread_mutex_lock(&frame_mutex); 
    pthread_cond_wait(&frame_cond, &frame_mutex); 
    pthread_mutex_unlock(&frame_mutex); 

    renderLinesArgs* arg = (renderLinesArgs*)pArg; 
    for(int y = arg->y1; y < arg->y2; y++){ 
     for(int x = 0; x < arg->width; x++){ 
      Color C = arg->scene->renderPixel(x, y); 
      putPixel(arg->screen, x, y, C); 
     } 
    } 

    sem_post(&frame_rendered); 
    } 
} 

참고 : 장면 -> renderPixel는 const를, 그래서 두 스레드가 같은 메모리에서 읽을 수 가정

내 스레드 기능은 다음과 같습니다.

//Signal a new frame 
pthread_mutex_lock(&frame_mutex); 
pthread_cond_broadcast(&frame_cond); 
pthread_mutex_unlock(&frame_mutex); 

//Wait for workers to be done 
sem_wait(&frame_rendered); 
sem_wait(&frame_rendered); 

//Unlock SDL surface and flip it... 

참고 : 내 메인 루프에서 내가 사용하여 이러한 작업을, 이렇게 두 작업자 스레드가 나는 또한 생성하고 동기화 대신 스레드에 가입 시도했습니다. "-lpthread -D_POSIX_PTHREAD_SEMANTICS -pthread"로 컴파일하고 gcc는 불평하지 않습니다.

최상의 실행 중에 CPU 사용률의 그래프를 이용하여 도시되어 내 문제 : CPU usage during execution. http://jopsen.dk/downloads/processor_usage.png

그래프에서 본 내 프로그램은 한번 그 두 매의 전환, 한 번에 하나 개의 코어를 사용하는 수 있듯이 그러나 잠시 후 100 %로 향상되지는 않습니다. 내가 뭘 잘못 했니? 장면에서 뮤텍스 나 세마포어를 사용하지 않습니다. 버그를 찾으려면 어떻게해야합니까?

scene-> renderPixel() 주위에 while (true)를두면 두 코어를 모두 100 %로 푸시 할 수 있습니다. 그래서 이것이 오버 헤드로 인해 발생했다고 생각했지만 복잡한 장면이있는 경우 0.5 초 (예 : FPS : 0.5) 만 동기화합니다. 내 버그가 무엇인지 말해주는 것이 쉽지 않을 수도 있지만, 디버깅에 대한 접근법도 좋을 것입니다 ... 전에 pthreads로 연주하지 않았습니다 ...

하드웨어 또는 커널 문제, 내 커널은 다음과 같습니다

$uname -a 
Linux jopsen-laptop 2.6.27-14-generiC#1 SMP Fri Mar 13 18:00:20 UTC 2009 i686 GNU/Linux 

참고 : 나는 어둠 속에서 야생 자상을하고 작업자 스레드가 조건 변수를 기다리는 많은 시간을 소비하고 말할 것

답변

2

이 쓸모가 :

pthread_mutex_lock(&frame_mutex); 
pthread_cond_wait(&frame_cond, &frame_mutex); 
pthread_mutex_unlock(&frame_mutex); 

새 프레임을 기다리는 기다리면

가 그런 짓을 :

INT new_frame = 0;

첫 번째 스레드 :

pthread_mutex_lock(&mutex); 
new_frame = 1; 
pthread_cond_signal(&cond); 
pthread_mutex_unlock(&mutex); 

다른 스레드 :

pthread_mutex_lock(&mutex); 
while(new_frame == 0) 
    pthread_cond_wait(&cond, &mutex); 
/* Here new_frame != 0, do things with the frame*/ 
pthread_mutex_unlock(&mutex); 

는 pthread_cond_wait()는 실제로 뮤텍스를 해제하고, 스레드 스케줄 해제 조건이 신호 할 때까지. 조건이 발생하면 스레드가 깨어나고 뮤텍스가 다시 처리됩니다. 이 모든 일은 pthread_cond_wait() 함수 안에서 발생합니다.

+0

이것은 도움이되었습니다. 이미지의 절반이 아닌 두 번째 줄마다 렌더링이 거의 동시에 같은 시간에 렌더링된다는 것을 발견했습니다. 결국 결국 코어를 100 %로 향상 시켰지만 프레임 속도는 향상되지 않았습니다 :) - 아니면 그냥 잘못 측정 한 것입니다 ... 도움을 주셔서 감사합니다 ... – jonasfj

+0

하하, 첫 번째 최적화 단계는 항상 n 프로세서와 병렬 알고리즘은 단일 프로세서를 사용하는 것보다 효율적입니다. 계속 노력하면 결국 개선 될 것입니다. – Ben

1

. 코드가 주로 CPU 바운드 인 이런 종류의 상황에서 좋은 CPU 성능을 얻으려면 스레드를 "풀"로 취급하고 큐 구조를 사용하여 작업을 처리 할 수있는 작업 지향 스타일의 프로그래밍을 사용하는 것으로 이해합니다 그들. 대기열에서 작업을 끌어 내고 실제 작업을하는 데 대부분의 시간을 소비해야합니다.

지금 당장 가지고있는 일은 잠시 동안 작업을하고있을 때 세마포어를 통해 메인 스레드에 통보한다는 것입니다. 주 스레드는 두 스레드가 현재 처리중인 프레임에서 작업을 마칠 때까지 스레드를 해제하지 않습니다.

C++을 사용하고 있으므로 Boost.Threads를 사용 해본 적이 있습니까? 다중 스레드 코드로 작업하는 것이 훨씬 쉬워졌으며, API는 사실 pthread와 유사하지만 "현대적인 C++"방식입니다.

1

나는 더 pthreads의 전문가는 아니지만, 다음과 같은 코드가 잘못 나에게 보인다

pthread_mutex_lock(&frame_mutex); 
pthread_cond_wait(&frame_cond, &frame_mutex); 
pthread_mutex_unlock(&frame_mutex); 

가 지정된 조건 까지 this article

pthread_cond_wait() 블록 호출 스레드를 인용 신호가 보내집니다. 이 루틴은 뮤텍스가 잠겨있는 동안 이 호출되어야하며, 기다리는 동안 뮤텍스가 자동으로 해제됩니다 ( ). 신호가 이고 수신 된 스레드가 깨어 난 후에 뮤텍스 은 스레드에 의해 자동으로 으로 잠김니다. 프로그래머는 스레드가 완료되면 뮤텍스 잠금 해제를 담당합니다.

그래서 당신이 후 pthread_cond_wait를 follwing을 코드 블록을 뮤텍스 를 해제해야한다고 나에게 보인다.