C 언어 에서 메 인 스 레 드 가 하위 스 레 드 에 미 치 는 영향 을 간단하게 알 수 있 습 니 다.

이 글 은 C 언어 에서 메 인 스 레 드 가 하위 스 레 드 에 미 치 는 영향 을 간단하게 알 아 보 는 것 을 소개 했다.글 에서 예시 코드 를 통 해 매우 상세 하 게 소개 되 었 고 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가 치 를 가지 기 때문에 필요 한 친 구 는 참고 할 수 있다.
프로그램 에 있어 서 주 프로 세 스 가 하위 프로 세 스 가 끝나 지 않 았 을 때 종료 되 었 다 면 리 눅 스 커 널 은 하위 프로 세 스 의 부모 프로 세 스 ID 를 1(즉 init 프로 세 스)로 바 꾸 고 하위 프로 세 스 가 끝 난 후에 init 프로 세 스 가 이 하위 프로 세 스 를 회수 합 니 다.
프로 세 스 를 스 레 드 로 바 꾸 면 어떻게 될까요?주 스 레 드 가 하위 스 레 드 가 끝나 기 전에 종료 되 었 다 고 가정 하면 하위 스 레 드 는 어떻게 됩 니까?
일부 포럼 에서 많은 사람들 이 서브 스 레 드 도 따라서 탈퇴 할 것 이 라 고 말 하 는 것 을 보 았 다.사실은 이것 은 잘못된 것 이다.왜냐하면 그들 은 스 레 드 탈퇴 와 프로 세 스 탈퇴 개념 을 헷 갈 렸 기 때문이다.실제 답 은 메 인 스 레 드 가 종 료 된 후 하위 스 레 드 의 상태 가 있 는 프로 세 스에 의존 하 는 것 입 니 다.프로 세 스 가 종료 되 지 않 았 다 면 하위 스 레 드 는 여전히 정상적으로 작 동 합 니 다.프로 세 스 가 종료 되면 모든 스 레 드 가 종료 되 기 때문에 하위 스 레 드 도 종 료 됩 니 다.
주 스 레 드 먼저 종료
먼저 메 인 스 레 드 가 먼저 종료 되 는 예 를 보 겠 습 니 다.

#include <pthread.h>
#include <unistd.h>

#include <stdio.h>

void* func(void* arg)
{
  pthread_t main_tid = *static_cast<pthread_t*>(arg);
  pthread_cancel(main_tid);
  while (true)
  {
    //printf("child loops
"); } return NULL; } int main(int argc, char* argv[]) { pthread_t main_tid = pthread_self(); pthread_t tid = 0; pthread_create(&tid, NULL, func, &main_tid); while (true) { printf("main loops
"); } sleep(1); printf("main exit
"); return 0; }
주 스 레 드 의 스 레 드 번 호 를 하위 스 레 드 에 전달 하고 하위 스 레 드 에서 pthreadcancel 에서 주 스 레 드 를 종료 합 니 다.프로그램 을 실행 하면 일정 수량의"main loops"를 인쇄 한 후에 프로그램 이 끊 겼 지만 종료 되 지 않 았 음 을 알 수 있 습 니 다.
메 인 스 레 드 는 이불 스 레 드 가 종료 되 었 기 때문에'main exit'의 인쇄 를 보지 못 했 습 니 다.하위 스 레 드 가 주 스 레 드 를 종료 한 후 순환 while 에 들 어 갔 기 때문에 프로그램 이 끊 긴 것 처럼 보 입 니 다.하위 프로 세 스 while 순환 에 있 는 인쇄 문 구 를 적용 하고 실행 하면 프로그램 이'child loops'라 는 글 자 를 계속 인쇄 하 는 것 을 발견 할 수 있 습 니 다.
메 인 스 레 드 는 하위 스 레 드 가 종료 되 었 으 나 그들 이 의존 하 는 프로 세 스 가 종료 되 지 않 았 기 때문에 하위 스 레 드 는 여전히 정상적으로 작 동 합 니 다.
메 인 라인 은 프로 세 스 와 함께 종료 합 니 다.
이전에 일부 사람들 은 메 인 스 레 드 가 먼저 종료 되면 하위 스 레 드 도 따라서 종료 된다 고 말 했 는데 사실은 스 레 드 종료 와 프로 세 스 종료 의 개념 을 헷 갈 렸 다.아래 의 이 예 는 그들의 관점 을 대표 한다.

void* func(void* arg)
{
  while (true)
  {
    printf("child loops
"); } return NULL; } int main(int argc, char* argv[]) { pthread_t main_tid = pthread_self(); pthread_t tid = 0; pthread_create(&tid, NULL, func, &main_tid); sleep(1); printf("main exit
"); return 0; }
위의 코드 를 실행 하면 프로그램 이 일정 수량의'child loops'와'main exit'를 인쇄 한 후에 종료 하고 종료 하기 전의 마지막 인쇄 는'main exit'입 니 다.
그들의 논리 에 따 르 면,보 세 요.메 인 스 레 드 가'main exit'를 인쇄 한 후에 종료 되 었 고,그 후에 하위 스 레 드 도 따라서 종료 되 었 기 때문에,그 후에 하위 스 레 드 의 인쇄 가 없습니다.
하지만 프로 세 스 종료 와 스 레 드 종료 라 는 개념 을 헷 갈 렸 다.실제 상황 은 메 인 스 레 드 의 main 함수 가 ruturn 후 스 택 을 실행 한 다음 glibc 라 이브 러 리 함수 exit,exit 를 호출 하여 관련 청 소 를 한 후 호출exit 시스템 호출 이 프로 세 스 를 종료 합 니 다.따라서 이러한 상황 은 실제 적 으로 프로 세 스 가 종료 되 었 기 때문에 모든 스 레 드 도 따라서 종료 되 었 습 니 다.메 인 스 레 드 의 종료 로 인해 서브 스 레 드 도 종료 되 는 것 이 아 닙 니 다.
Linux 스 레 드 모델
실제로 poix 스 레 드 는 일반적인 프로 세 스 와 달리 개념 적 으로 메 인 스 레 드 와 서브 스 레 드 의 구분 이 없다(실제 실현 에 있어 서 일부 구분 이 있 지만).apue 나 unp 등 책 을 자세히 살 펴 보면'메 인 스 레 드'나'서브 스 레 드'등 단 어 를 거의 볼 수 없고 csapp 에서 심지어'대등한 스 레 드'라 는 단어 로 스 레 드 간 의 관 계 를 묘사 할 수 있다.
Linux 2.6 이후 의 posix 스 레 드 는 모두 사용자 상태의 pthread 라 이브 러 리 에서 이 루어 집 니 다.pthread 라 이브 러 리 를 사용 한 후 사용자 의 시각 에서 볼 때 모든 taststruct 는 하나의 스 레 드 에 대응 합 니 다(taststruct 는 원래 커 널 이 하나의 프로 세 스 에 대응 하 는 구 조 였 으 며,스 레 드 와 그들 이 공동으로 참조 하 는 자원 은 프로 세 스 였 다.Linux 2.6 부터 커 널 에 스 레 드 그룹의 개념 이 있 습 니 다.taststruct 구조 에 tgid(thread group id)필드 가 추가 되 었 습 니 다.getpid(프로 세 스 번호 가 져 오기)시스템 호출 을 통 해 되 돌아 오 는 것 도 taststruct 의 tgid 이기 때문에 tgid 는 프로 세 스 번호 입 니 다.그리고 taststruct 의 스 레 드 번호 pid 필드 는 시스템 에서 syscall(SYSgettid)가 져 옵 니 다.
스 레 드 가 kill 치 명 적 인 신 호 를 받 았 을 때 커 널 은 처리 동작 을 전체 스 레 드 그룹 에 가 합 니 다.'프로 세 스에 보 내 는 신호'와'스 레 드 에 보 내 는 신호'에 대응 하기 위해 taststruct 에서 시그 널 두 세트 를 지 켰 습 니 다pending,한 세트 는 스 레 드 그룹 이 공유 하고 한 세트 는 스 레 드 만 있 습 니 다.kill 을 통 해 보 내 는 치 명 적 인 신 호 를 스 레 드 그룹 에 공유 하 는 signalpending 에 서 는 임의의 스 레 드 로 처리 할 수 있 습 니 다.pthread 를 통 해kill 에서 보 낸 신 호 는 스 레 드 만 의 signalpending 에 서 는 이 스 레 드 로 만 처리 할 수 있 습 니 다.
스 레 드 와 신호 에 대해 apue 는 다음 과 같은 몇 마디 가 있 습 니 다.
모든 스 레 드 는 자신의 신호 차단 자 를 가지 고 있 지만 신호 처 리 는 프로 세 스 의 모든 스 레 드 가 공유 합 니 다.이것 은 하나의 스 레 드 가 일부 신 호 를 막 을 수 있 지만 스 레 드 가 특정한 신호 와 관련 된 처리 행 위 를 수정 한 후에 모든 스 레 드 는 이 처리 행위 의 변 화 를 공유 해 야 한 다 는 것 을 의미한다.이렇게 하면 한 스 레 드 가 특정한 신 호 를 무시 하고 다른 스 레 드 는 신호 의 기본 처리 행 위 를 회복 하거나 신호 에 새로운 처리 프로그램 을 설정 하여 상기 스 레 드 의 신호 선택 을 취소 할 수 있 습 니 다.
만약 신호 의 기본 처리 동작 이 이 프로 세 스 를 종료 하 는 것 이 라면,신 호 를 특정한 라인 에 전달 하면 전체 프로 세 스 를 죽 일 것 이다.
예 를 들 어 하나의 프로그램 a.out 에서 키 라인 을 만 들 었 습 니 다.메 인 라인 의 라인 번호 가 9601 이 고,하위 라인 의 라인 번 호 는 9602(그들의 tgid 는 모두 9601)입 니 다.기본적으로 신호 처리 프로그램 이 설정 되 어 있 지 않 기 때문에 명령 kill 9602 를 실행 하면 9601 과 9602 두 라인 을 함께 죽 일 수 있 습 니 다.Linux 스 레 드 뒤의 이 야 기 를 모 르 면 이상 한 사건 을 만 났 다 고 느 낄 수 있 습 니 다.
다른 시스템 호출 syscall(SYSgettid)가 져 온 스 레 드 번호 와 pthreadself 가 가 져 온 스 레 드 번 호 는 다 릅 니 다.pthreadself 에서 가 져 온 스 레 드 번 호 는 스 레 드 가 의존 하 는 프로 세 스 내부 에서 만 유일 합 니 다.pthreadself 의 man page 에는 다음 과 같은 말 이 있 습 니 다.
Thread IDs are guaranteed to be unique only within a process. A thread ID may be reused after a terminated thread has been joined, or a detached thread has terminated.
그래서 커 널 에서 유일 하 게 스 레 드 ID 를 표시 하 는 스 레 드 번 호 는 시스템 을 통 해 syscall(SYSgettid)가 져 오기.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기