IT이야기

아직 실행 중인지 확인하기 위해 pthread를 어떻게 쿼리하십니까?

cyworld 2022. 5. 24. 21:58
반응형

아직 실행 중인지 확인하기 위해 pthread를 어떻게 쿼리하십니까?

내 파괴자 안에서 나는 실을 깨끗이 부수고 싶다.

내 목표는 스레드가 실행을 마칠 때까지 기다렸다가 스레드를 파괴하는 것이다.

pthread의 상태를 쿼리하는 데 대해 내가 찾은 유일한 것은 pthread_attr_setdetachstate이지만 이것은 오직 당신의 스레드가 다음과 같은 경우에만 말해준다.

  • PTHREAD_CREATE_DETHED
  • PTHREAD_CREATE_JOABLE

둘 다 실이 아직 가동 중인지 여부와는 무관하다.

아직 실행 중인지 확인하기 위해 pthread를 어떻게 쿼리하십니까?

두 가지 질문이 있는 것 같군

스레드가 완료될 때까지 어떻게 기다릴 수 있는가?

답변: 이 기능은 pthreads에 의해 직접 지원됨 - 스레드 대 스톱 조이너블(처음 시작할 때)을 만들고 pthread_join()을 사용하여 스레드가 더 이상 실행되지 않을 때까지 현재 스레드를 차단하십시오.


내 실이 아직 작동 중인지 어떻게 알 수 있을까?

답변: "thread_complete" 플래그를 추가하여 다음 작업을 수행하십시오.

시나리오:스레드 A는 스레드 B가 아직 살아 있는지 알고 싶어한다.

스레드 B가 생성되면 "thread_complete" 플래그 주소에 대한 포인터가 주어진다.스레드가 생성되기 전에 "thread_complete" 플래그를 NOT_COMPLE로 초기화해야 한다.스레드 B의 진입점 함수는 즉시 pthread_cleanup_push()를 호출하여 "thread_complete" 플래그를 완료로 설정하는 "정리 핸들러"를 푸시해야 한다.

정리 처리기에 대한 자세한 내용은 여기를 참조하십시오: pthread 정리 처리기

해당 pthread_cleanup_pop(1) 호출을 포함하여 어떤 일이 있어도 정리 처리기가 호출되도록 하십시오(즉, 스레드가 정상적으로 OR을 종료하는 경우 등).

그러면 스레드 A가 "스레드_완전" 플래그를 확인하여 스레드 B가 아직 종료되지 않았는지 확인할 수 있다.

참고: "스프레드_완전" 플래그는 "휘발성"으로 선언되어야 하며 원자 유형이어야 한다. GNU 컴파일러는 이를 위해 sig_atomic_t를 제공한다.이를 통해 두 스레드는 동기화 구성(mutexes/semaphores) 없이도 동일한 데이터에 일관성 있게 액세스할 수 있다.

내가 "승리"라는 대답에 대해 주목해보자. 이 답은 거대한 숨겨진 결함을 가지고 있고, 어떤 맥락에서 그것은 충돌로 이어질 수 있다.pthread_join을 사용하지 않는 한 계속 올라올 것이다.프로세스와 공유 라이브러리가 있다고 가정해 보십시오.도서관에 lib.so으로 전화하십시오.

  1. 그걸 열면 실이 들어가기 시작하는 거야결합을 원하지 않는다고 가정해 분리할 수 있도록 설정하십시오.
  2. 리브의 논리를 처리하고 공유하며 작업을 수행하는 등...
  3. 당신은 더 이상 필요하지 않기 때문에 lib.so을 로드하고 싶어한다.
  4. 스레드의 셧다운을 호출하면, 당신은 나중에 lib.so의 스레드에서 깃발을 읽기를 원하며, 그것이 끝났다고 말한다.
  5. 여러분이 봤듯이, 깃발이 이제 그 실을 "완료된" 것으로 보여주고 있기 때문에, 당신은 dlclose로 다른 실을 계속 이어간다.
  6. dlclose는 모든 스택과 코드 관련 메모리를 로딩한다.
  7. Whops, 그러나 dlclose는 실을 멈추게 하지 않는다.그리고 알다시피, 여러분이 "스프레드가 끝났어" 휘발성 원자 깃발 변수를 설정하기 위해 청소 핸들러의 마지막 줄에 있을 때에도, 여러분은 여전히 스택의 많은 방법으로부터 돌아와야 하고, 값을 되돌려 주어야 한다.#5+#6의 스레드에 큰 스레드의 우선 순위가 부여되었다면, 스레드에서 정말로 스레드를 멈출 수 있기 전에 dlclose를 받게 될 것이다.가끔 멋진 충돌 사고가 날 거야.

지적할게, 이건 골반신학적 문제가 아니야, 나도 우리 프로젝트에서 같은 문제가 있었어.

완전한 휴대용 솔루션은 없지만, 플랫폼이 pthread_tryjoin_np 또는 pthread_timedjoin_np를 지원하는지 확인하십시오.따라서 스레드가 결합될 수 있는지(물론 PTHREAD_CREATE_J로 생성됨)만 확인하십시오.OABLE.

pthread_join()으로 전화하면 될 것 같아.그 전화는 실이 꺼질 때까지 돌아오지 않을 것이다.

스레드가 아직 실행 중인지 아닌지를 확인하기 위해 폴링을 하려면(그리고 보통은 그렇게 하고 싶지 않다는 점을 유의하십시오!), 스레드가 나오기 직전에 휘발성 부울을 false로 설정하도록 할 수 있다.네 본인도 부울을 읽을 수 있고 그게 사실이라면 실이 아직 작동 중이라는 걸 알 거야(잘못된 경우, 반면에, 스레드는 적어도 거의 사라졌다는 것을 알고 있다; 그래도 여전히 부울을 거짓으로 설정한 후에 발생하는 정리 코드를 실행하고 있을 수 있으므로, 이 경우에도 스레드가 접근할 수 있는 리소스를 확보하기 전에 pthread_message를 호출해야 한다.)

#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>

void* thread1 (void* arg);
void* thread2 (void* arg);

int main()
{
    pthread_t thr_id;

    pthread_create(&thr_id, NULL, thread1, NULL);

    sleep(10);
}

void* thread1 (void* arg)
{
    pthread_t thr_id = 0;

    pthread_create(&thr_id, NULL, thread2, NULL);

    sleep(5);
    int ret = 0;
    if( (ret = pthread_kill(thr_id, 0)) == 0)
    {
        printf("still running\n");
        pthread_join(thr_id, NULL);
    }
    else
    {
        printf("RIP Thread = %d\n",ret);
    }
}

void* thread2 (void* arg)
{
//  sleep(5);
    printf("I am done\n");
}
pthread_kill(tid, 0);

신호는 전송되지 않지만 오류 확인은 계속 수행되므로 이를 사용하여 티드의 존재를 확인할 수 있다.

주의: 이 답은 틀렸다.이 표준은 특히 수명이 끝난 실의 ID 통과를 금지하고 있다.이 ID는 이제 다른 스레드를 지정하거나, 더 나쁘게 말하면, 해제된 메모리를 참조하여 충돌을 유발할 수 있다.

최소한 리눅스에서는 효과가 있는 솔루션을 생각해 냈다고 믿는다.스레드를 생성할 때마다 스레드를 LWP(경량 프로세스 ID)로 저장하고 고유한 이름(예: intlwp = syscall(SYS_getid), prctl(PR_SET_NAME, (long)"unique name", 0, 0, 0);

그런 다음 나중에 스레드가 존재하는지 확인하기 위해 /proc/pid/task/lwp/comm을 열고 읽는다.파일이 존재하고 파일의 내용이 내가 할당한 고유 이름과 일치하면 스레드가 존재한다.이는 삭제/재사용 가능한 TID를 라이브러리 기능에 전달하지 않으므로 충돌이 발생하지 않는다는 점에 유의하십시오.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <sys/file.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <syscall.h>

pthread_t subthread_tid;
int       subthread_lwp;

#define UNIQUE_NAME "unique name"

bool thread_exists (pthread_t thread_id)
{
    char path[100];
    char thread_name[16];
    FILE *fp;
    bool  thread_exists = false;

    // If the /proc/<pid>/task/<lwp>/comm file exists and it's contents match the "unique name" the
    // thread exists, and it's the original thread (TID has NOT been reused).

    sprintf(path, "/proc/%d/task/%d/comm", getpid(), subthread_lwp);

    fp = fopen(path, "r");

    if( fp != NULL ) {

        fgets(thread_name, 16, fp);
        fclose(fp);

        // Need to trim off the newline
        thread_name[strlen(thread_name)-1] = '\0';

        if( strcmp(UNIQUE_NAME, thread_name) == 0 ) {
            thread_exists = true;
        }
    }

    if( thread_exists ) {
        printf("thread exists\n");
    } else {
        printf("thread does NOT exist\n");
    }

    return thread_exists;
}


void *subthread (void *unused)
{
    subthread_lwp = syscall(SYS_gettid);
    prctl(PR_SET_NAME, (long)UNIQUE_NAME, 0, 0, 0);

    sleep(10000);

    return NULL;
}


int main (int argc, char *argv[], char *envp[])
{
    int error_number;

    pthread_create(&subthread_tid, NULL, subthread, NULL);
    printf("pthread_create()\n");
    sleep(1);
    thread_exists(subthread_tid);

    pthread_cancel(subthread_tid);
    printf("pthread_cancel()\n");
    sleep(1);
    thread_exists(subthread_tid);

    error_number = pthread_join(subthread_tid, NULL);
    if( error_number == 0 ) {
        printf("pthread_join() successful\n");
    } else {
        printf("pthread_join() failed, %d\n", error_number);
    }
    thread_exists(subthread_tid);

    exit(0);
}

참조URL: https://stackoverflow.com/questions/2156353/how-do-you-query-a-pthread-to-see-if-it-is-still-running

반응형