2012-04-03 4 views
0

커널에 갈 필요없이 다른 스레드의 레지스터 또는 스레드 로컬 변수를 직접 읽을 수 있습니까? 그렇게하는 가장 좋은 방법은 무엇입니까?다른 스레드의 레지스터 또는 스레드 로컬 변수 읽기

+0

[ptrace] (http://linux.die.net/man/2/ptrace)? –

+0

빠른 솔루션이 필요합니다. ptrace가 너무 느립니다. 그리고 ptrace는 커널을 사용해야합니다. – pythonic

+3

왜이 작업을 수행해야합니까? –

답변

1

어쨌든 유용하지 않을 레지스터는 읽을 수 없습니다. 그러나 을 읽고 다른 스레드의 스레드 로컬 변수을 쉽게 읽을 수 있습니다.

아키텍처에 따라 (예 : x86_64와 같은 강력한 메모리 순서 지정) 동기화없이 안전하게 수행 할 수 있습니다. 단, 읽기 값은 스레드가 어떤 방식 으로든 영향을 미치지 않습니다. 시나리오는 스레드 로컬 카운터 또는 이와 유사한 것을 표시합니다.

특히 당신이 태그로 x86_64의에 리눅스에서, 당신은 그런를 위해 할 수있는 :

// A thread local variable. GCC extension, but since C++11 actually part of C++ 
__thread int some_tl_var; 

// The pointer to thread local. In itself NOT thread local, as it will be 
// read from the outside world. 
struct thread_data { 
    int *psome_tl_var; 
    ... 
}; 

// the function started by pthread_create. THe pointer needs to be initialized 
// here, and NOT when the storage for the objects used by the thread is allocated 
// (otherwise it would point to the thread local of the controlling thread) 
void thread_run(void* pdata) { 
    pdata->psome_tl_var = &some_tl_var; 

    // Now do some work... 
    // ... 
} 

void start_threads() { 
    ... 
    thread_data other_thread_data[NTHREADS]; 
    for (int i=0; i<NTHREADS; ++i) { 
     pthread_create(pthreadid, NULL, thread_run, &other_thread_data[i]);  
    } 

    // Now you can access each some_tl_var as 
    int value = *(other_thread_data[i].psome_tl_var); 
    ... 
} 

내가 작업자 스레드에 대한 통계를 표시하기위한 유사한 사용. C++에서 훨씬 더 쉽습니다. 스레드 주위에 객체를 만들면 thread 클래스에 대한 포인터를 스레드 클래스의 필드로 만들고 액세스는 멤버 함수로만 이루어집니다.

면책 조항 : 이식성이 없지만 x86_64, linux, gcc에서 작동하며 다른 플랫폼에서도 작동 할 수 있습니다.

1

커널을 포함시키지 않고서는 그것을 수행 할 방법이 없으며 실제로 어떤 종류의 동기화가 없으면 그것을 읽는 것이 의미가 있다고 생각하지 않습니다. ptrace (추악하고 휴대 가능하지 않음)을 사용하고 싶지 않다면 "수신자 등록/TLS 보내기"메시지에 사용할 실시간 신호 중 하나를 선택할 수 있습니다. 대략적인 아이디어는 다음과 같습니다.

  1. 요청에 대해 전역 뮤텍스를 잠급니다.
  2. 전역 변수의 스레드에서 원하는 데이터 (예 : pthread_key_t 또는 특수 값 의미 레지스터)에 대한 정보를 저장합니다.
  3. pthread_kill으로 대상 스레드 신호를 보냅니다. (sigactionSA_SIGINFO 설치된 했어야) 신호 처리기
  4. 는 요청에 전역 변수 ucontext_t 다시 통신하기 위해 사용하는 것이 복사 (실제로 ucontext_t 가리키는) 신호 처리기 제 void * 인수를 사용 실. 이렇게하면 모든 레지스터 값과 많은 정보가 제공됩니다. pthread_getspecific은 비동기 신호에 안전하지 않고 기술적으로이 컨텍스트에서 실행하기에는 적합하지 않기 때문에 TLS는 좀 더 까다 롭습니다.하지만 실제로는 작동합니다.
  5. 신호 처리기는 요청 스레드에 완료되었음을 알리는 세마포어 (POSIX에서 제공하는 유일한 비동기 신호 안전 동기화 기능)를 게시하고 리턴합니다.
  6. 요청하는 스레드는 세마포어를 기다리고 완료 한 다음 데이터를 읽고 요청 뮤텍스를 잠금 해제합니다. 이는 하나를 요청하는 스레드 (pthread_kill)를 kernelspace 적어도 1 전이를 포함 (그리고 아마도 다른 sem_wait)에서, 상기 신호 처리기로부터 반환 대상 글 1-3 (1 것이라는

참고 신호 처리기가 커널 공간에서 아직 잠자지 않았 으면 입력하고, 가능하면 sem_post을 입력하십시오. 여전히 고성능 사용을 위해 설계되지 않은 ptrace을 사용하는 것이 더 빠를 것입니다 ...

+0

아, 그건 내 목적을 위해 천천히하는 것입니다. 지금까지 내가 해왔 던 일, 즉 글로벌 배열을 사용하는 데 전념 할 것입니다. – pythonic

+0

@ user1018562 여러 스레드에서 액세스하는 전역 배열은 캐시 동기화, 스누핑 등으로 인해 심각한 성능 저하를 초래할 수 있습니다. – hirschhornsalz