2012-01-20 2 views
2

Boost :: threads를 사용하여 스레드 된 클래스에 이상한 문제가있다. 다음은 내가하는 일에 대한 간략한 요약입니다.임베디드 ARM에서 부스터 오류를 일으키는 Boost :: Thread 함수

루틴은 상속 트리를 형성하는 기본 클래스에 대한 공유 포인터 인 개인 데이터 멤버를 사용하여 처리기 클래스로 구성된 많은 개체를 만듭니다 . 나는이 루틴이 올바르게 작동하고 있으며 문제의 일부가 아니라는 것을 확신한다.

그런 다음 스레드 클래스의 새 인스턴스를 만드는 처리기 클래스 (startUpdate) 메서드를 호출합니다. 다음은 스레드 클래스 코드는 다음과 같습니다

class Sensor_Thread 
{ 
    public: 
    //constructor (creates thread and binds the update function to it 
    Sensor_Thread (const Ptr<Sensor_Base> & theSensor): m_stoprequested (false), 
         s (theSensor), 
         m_thread (boost::bind (&Sensor_Thread::update, this)) { } 
    //default null constructor, shouldn't ever be used 
    Sensor_Thread(): m_stoprequested (true), 
         m_thread(), 
         s (NULL) { } 

    //destructor (automatically joins the thread as per RAII principles) 
    ~Sensor_Thread() { m_stoprequested = true; m_thread.join(); } 

    private: 
    volatile bool m_stoprequested; 
    boost::mutex m_mutex; 
    boost::thread m_thread; 
    Ptr<Sensor_Base> s; 

    void update(); 

}; 

(이하 "의 PTR"클래스가 내 공유 포인터 클래스 ... 나는 ... 나는 원래 C++ 교과서에서 그것을 가지고 있기 때문에 제대로 작동 상당히 확신)

업데이트 기능 : 드라이버에서 다른 트리거가 stopUpdate를 호출하고 threaded_class가 파괴 될 때까지

void Sensor_Thread::update() 
{ 
    //make sure we actually have a sensor attached... 
    if (s) { 
    // set up structure for sleeping 
    struct timespec time; 
    while (!m_stoprequested) 
    { 
     boost::mutex::scoped_lock lock(m_mutex); 
     s->update(); 
     time.tv_sec = s->updateInterval/1000; 
     time.tv_nsec = (1000 % s->updateInterval) * (1000 * 1000); 
     nanosleep (&time, NULL); 
    } 
    } 
} 

이 무기한 실행됩니다.

이상한 점 : 내 개발 상자에서 darwin gcc 4.2.1을 사용하는 OS X 10.6에서 예상대로 정확하게 작동합니다.

이것은 debian linux와 ARM 프로세서가있는 임베디드 서버에서 실행하기위한 것입니다. 임베디드 시스템 제조업체가 제공하는 교차 컴파일 툴체인을 가지고 있으며이 크로스 컴파일에 사용할 때 seg fault가 발생합니다. 디버깅을 통해 s-> update()가 호출 될 때 (또는 공유 포인터를 역 참조하고 다른 것을 시도 할 때)이 seg 오류가 발생 함을 발견했습니다. 그러나 약간의 지연이있을 경우 "sleep (1);"을 추가하여 말하십시오. 내 Sensor_Thread :: update 함수에서 while 루프를 시작하기 전에 완벽하게 작동합니다.

내 마음에, 이것은 완전히 또는 적절하게 초기화되기 전에 시스템이 공유 포인터를 역 참조하려고한다는 것을 암시하는 것처럼 보입니다. 수면 (1)으로 해결하면 효과가 있지만 여전히 이상하게 보입니다. 스레드 된 클래스의 공유 포인터가 생성자 중에 초기화되면 업데이트 기능이 호출되기 전에 준비가되어 있지 않아야합니까? 또는 boost :: thread를 생성한다는 것은 업데이트 된 함수가 스레드 된 클래스가 소유하는 공유 포인터의 초기화와 동시에 발생한다는 것을 의미합니까? 업데이트 함수가 호출되기 전에 공유 포인터가 초기화되었는지 확인하기 위해 "잠자기"해킹보다 더 깨끗한 방법이 있습니까?

감사합니다 !!!

+0

교과서에 대한 당신의 신념은 매우 매력적입니다. :) – sarnold

답변

3
Sensor_Thread (const Ptr<Sensor_Base> & theSensor): m_stoprequested (false), 
        s (theSensor), 
        m_thread (boost::bind (&Sensor_Thread::update, this)) { } 

이 코드는 깨졌습니다. 아직 구성되지 않은 오브젝트에 update을 호출 중입니다. 생성자의 초기화 목록에 this을 사용하면 항상 빨간색 플래그가 발생합니다. 아직 완전히 존재하지 않는 객체에 대한 포인터입니다.

일반적인 방법은 두 단계로 나누는 것입니다. 스레드를 만드는 방법은 run 또는 start입니다. 생성자가 반환 된 후에 해당 메서드를 호출합니다.

while (!m_stoprequested) 
{ 
    boost::mutex::scoped_lock lock(m_mutex); 
    s->update(); 
    time.tv_sec = s->updateInterval/1000; 
    time.tv_nsec = (1000 % s->updateInterval) * (1000 * 1000); 
    nanosleep (&time, NULL); 
} 

이것은 아마도 원하는 것이 아닙니다. 뮤텍스가 항상 인데이므로 다른 스레드가 s에 액세스하는 것을 매우 어렵게 만듭니다. 다음 업데이트까지 기다렸다가 뮤텍스 경주에서 승리해야합니다.일부 플랫폼에서는 실제 작업을 수행하는 스레드가 '대화 형'스레드 (대부분 잠자기)를 때리는 데 어려움을 겪습니다. 따라서 이로 인해 상당량의 s에 액세스하려고 시도하는 다른 스레드가 느려질 수 있습니다.

왜 뮤텍스를 잡고있는 동안 nanosleep으로 전화를 걸립니까?

+0

고마워요! 시동기 방법을 추가 할 수있을만큼 쉬워야합니다. 당신이 아마 말할 수 있듯이, 나는 멀티 쓰레드 프로그래밍에 익숙하지 않다. 나는 이것을 온라인에서 찾은 예제를 기반으로하고있다 ... 나는 아마도 뮤텍스에 대해 약간 혼란 스럽다. 내 목표는 s -> update() 메서드가 실행되는 동안 다른 객체가 가리키는 포인터 (s가 공유 포인터)를 가리 키지 않도록하는 것입니다. nanosleep 함수는 업데이트 간격을 설정하는 중이고 뮤텍스 내부에있을 필요가 없습니다 ... 내 목표를 가장 잘 달성하는 방법에 대한 통찰력이 있습니까? – bencpeters

+0

scoped_lock을 제거하고 mutex를'update' 전에 잠그고 나중에 잠금을 해제 할 수 있습니다. 또는 scoped_lock과'update' 호출을'if 1' 블록 안에 넣을 수도 있습니다. (만약 다른 쓰레드가 *'*'s'를 수정한다면, 두개의 계산을 잠금 안에 넣으십시오. 그렇지 않으면, 가능한 한 적은 명령에 대해 뮤텍스를 유지하는 것이 일반적입니다. –

관련 문제