문제

가상 메소드가있는 클래스 인스턴스를 만들고 pthread_create로 전달하려고하면 레이스 조건이 생겨 발신자가 때때로 파생 된 메소드 대신 기본 메소드를 호출 할 수 있습니다. 인터넷 검색 후 pthread vtable race, 나는 이것이 상당히 잘 알려진 행동이라는 것을 알았습니다. 내 질문은, 그것을 돌아 다니는 좋은 방법은 무엇입니까?

아래 코드는 모든 최적화 설정 에서이 동작을 보여줍니다. Mythread 객체는 pthread_create로 전달되기 전에 완전히 구성됩니다.

#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Thread {
    pthread_t thread;

    void start() {
        int s = pthread_create(&thread, NULL, callback, this);
        if (s) {
            fprintf(stderr, "pthread_create: %s\n", strerror(errno));
            exit(EXIT_FAILURE);
        }
    }
    static void *callback(void *ctx) {
        Thread *thread = static_cast<Thread*> (ctx);
        thread->routine();
        return NULL;
    }
    ~Thread() {
        pthread_join(thread, NULL);
    }

    virtual void routine() {
        puts("Base");
    }
};

struct MyThread : public Thread {
    virtual void routine() {

    }
};

int main() {
    const int count = 20;
    int loop = 1000;

    while (loop--) {
        MyThread *thread[count];
        int i;
        for (i=0; i<count; i++) {
            thread[i] = new MyThread;
            thread[i]->start();
        }
        for (i=0; i<count; i++)
            delete thread[i];
    }

    return 0;
}
도움이 되었습니까?

해결책

여기서 유일한 문제는 스폰 된 스레드가 메소드를 실행하기 전에 물체를 삭제하고 있다는 것입니다. 따라서 그때까지 어린이 소멸자가 이미 발사되었고 개체가 더 이상 존재하지 않습니다.

따라서 pthread_create와 관련이 없습니다. 타이밍, 스레드를 생성하고, 자원을주고, 사용하기 전에 삭제할 수 없습니다.

이것을 시도하면 스폰 된 스레드를 사용하기 전에 OBJ가 메인 스레드에 의해 어떻게 파괴되는지 보여줍니다.

struct Thread {
pthread_t thread;
bool deleted;

void start() {
    deleted=false;
    int s = pthread_create(&thread, NULL, callback, this);
    if (s) {
            fprintf(stderr, "pthread_create: %s\n", strerror(errno));
            exit(EXIT_FAILURE);
    }
}
static void *callback(void *ctx) {
    Thread *thread = static_cast<Thread*> (ctx);
    thread->routine();
    return NULL;
}
~Thread() {
    pthread_join(thread, NULL);
}

virtual void routine() {
    if(deleted){
        puts("My child deleted me");
    }
    puts("Base");
}
};

struct MyThread : public Thread {
virtual void routine() {

}
~MyThread(){
    deleted=true;
}

};

반면에 스폰 된 스레드가 유효한 리소스를 사용하기 때문에 그 문제를 삭제하기 전에 메인에 잠을 자면 그 문제가 없습니다.

int main() {
const int count = 20;
int loop = 1000;

while (loop--) {
    MyThread *thread[count];
    int i;
    for (i=0; i<count; i++) {
            thread[i] = new MyThread;
            thread[i]->start();
    }
    sleep(1);
    for (i=0; i<count; i++)
            delete thread[i];
}

return 0;
}

다른 팁

파괴자에서 pthread_join (또는 다른 실제 작업)을하지 마십시오. joit () 메소드를 추가하여 스레드를 삭제하고 메인에서 스레드 [i]를 삭제하기 전에 호출하십시오.

Destructor에서 pthread_join을 호출하려고하면 스레드가 여전히 실을 실행 중일 수 있습니다. 즉, 객체를 사용하고 있음을 의미합니다 이미 부분적으로 파괴되었습니다. 무슨 일이 일어날 것? 누가 알아? 희망적으로 프로그램이 빠르게 충돌합니다.


또한 :

  • 스레드에서 상속하려면 스레드 :: ~ 스레드가 가상으로 선언되어야합니다.

  • 모든 오류를 확인하고 올바르게 처리하십시오 (BTW는 파괴자 내부에서 수행 할 수 없습니다).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top