>  기사  >  운영 및 유지보수  >  Linux 시스템 프로그래밍(pthread) 스레드 생성 및 사용에 대한 심층적인 이해

Linux 시스템 프로그래밍(pthread) 스레드 생성 및 사용에 대한 심층적인 이해

WBOY
WBOY앞으로
2022-02-02 07:00:312630검색

이 기사는 Linux에서 스레드 생성 및 사용에 대한 지식을 제공하는 데 도움이 되기를 바랍니다.

Linux 시스템 프로그래밍(pthread) 스레드 생성 및 사용에 대한 심층적인 이해

1. 소개

스레드와 프로세스의 차이점 (1) 프로세스: 운영체제 스케줄링의 가장 작은 단위입니다. Linux에서는 ps, top 등의 명령어를 통해 프로세스의 상세 정보를 볼 수 있습니다. (2) 스레드: 프로세스 스케줄링의 최소 단위입니다. 각 프로세스에는 메인 스레드가 있습니다. 프로세스에서 가장 중요한 일은 스레드입니다.

(3) 전체 시스템에서 프로세스 ID는 고유 식별자이며 프로세스 관리는 PID를 통해 이루어집니다. 프로세스가 생성될 때마다 커널은 프로세스에 대한 모든 정보를 저장하는 구조를 생성합니다. 프로세스 정보를 저장하는 각 노드에는 자체 PID도 저장됩니다. 프로세스를 관리해야 하는 경우 이 ID를 사용하여 이를 달성할 수 있습니다(예: 신호 전송). 자식 프로세스가 종료되어 재활용되어야 하는 경우(자식 프로세스가 종료하기 위해 exit()를 호출하거나 코드가 실행됨) wait() 시스템 호출을 통해 수행되어야 합니다. 재활용되지 않은 죽은 프로세스는 좀비 프로세스와 해당 프로세스 엔터티는 더 이상 존재하지 않지만 PID 자원을 차지하므로 재활용이 필요합니다.

스레드의 경우 적극적으로 종료하려면 pthread_exit()를 호출해야 하며, 메인 스레드는 pthread_join()을 호출하여 재활용해야 합니다(스레드가 "분리 속성"을 설정하지 않은 경우). 스레드와 같은 스레드 신호 전송도 스레드 ID를 통해 이루어집니다.

프로세스 간 통신 방법: A. 공유 메모리 B. 메시지 큐 C. 세마포 D. 명명된 파이프 E. 명명되지 않은 파이프 F. 신호 G. 파일 H. 스레드 간 소켓 통신 방법 : A. 뮤텍스 B. 스핀 잠금 C. 조건 변수 D. 읽기-쓰기 잠금 E. 스레드 신호 F. 전역 변수

프로세스 간에 사용되는 통신 방법은 커널 컨텍스트를 전환하거나 주변 장치(네임드 파이프, 파일)에 액세스해야 합니다. 그래서 속도가 느려지겠죠. 쓰레드가 자신만의 고유한 통신 방식을 사용한다면 기본적으로 자신의 프로세스 공간에서 완료되며, 스위칭이 없으므로 통신 속도가 빨라진다. 즉, 종류의 차이 외에도 프로세스와 스레드 간에 사용되는 통신 방식에 따라 속도도 다릅니다.

참고: 여러 스레드를 실행하는 프로세스가 신호를 포착하면 기본 스레드만 차단되고 다른 하위 스레드는 영향을 주지 않고 계속 실행됩니다.

2. 스레드 관련 함수 소개

2.1 스레드 생성

pthread_create는 유닉스 운영체제(유닉스, 리눅스 등)에서 스레드를 생성하는 함수이다. 컴파일할 때 링크 라이브러리를 지정해야 합니다. -lpthread 함수 프로토타입

#include <pthread.h>
int pthread_create
(
pthread_t *thread, 
const pthread_attr_t *attr,
void *(*start_routine) (void *), 
void *arg
);

매개변수 소개

첫 번째 매개변수는 스레드 식별자에 대한 포인터입니다. 두 번째 매개변수는 스레드 속성을 설정하는 데 사용됩니다. 기본적으로 NULL을 채울 수 있습니다. 세 번째 매개변수는 스레드 실행 함수의 시작 주소입니다. 마지막 매개변수는 함수를 실행하기 위한 매개변수입니다. 매개변수는 필요하지 않으며 NULL을 채울 수 있습니다. Linux에서 함수 도움말 보기: # man pthread_create

Linux 시스템 프로그래밍(pthread) 스레드 생성 및 사용에 대한 심층적인 이해

반환 값: 스레드가 성공적으로 생성되면 0이 반환됩니다. 스레드 생성에 실패하면 오류 번호가 반환됩니다. 스레드가 성공적으로 생성된 후 attr 매개변수는 다양한 스레드 속성을 지정하는 데 사용됩니다. 새로 생성된 스레드는 start_rtn 함수의 주소에서 실행을 시작합니다. 이 함수에는 하나의 범용 포인터 매개변수 arg만 있습니다. 스레드 작업 함수에 두 개 이상의 매개변수를 전달해야 하는 경우 이러한 매개변수를 구조에 넣어야 합니다. 그런 다음 이 구조의 주소가 arg 매개변수로 전달됩니다.

예:

#include <stdio.h>
#include <pthread.h>
//线程函数1
void *pthread_func1(void *arg)
{
    while(1)
    {
        printf("线程函数1正在运行.....\n");
        sleep(2);
    }
}
//线程函数2
void *pthread_func2(void *arg)
{
    while(1)
    {
        printf("线程函数2正在运行.....\n");
        sleep(2);
    }
}
int main(int argc,char **argv)
{
    
    pthread_t thread_id1;
    pthread_t thread_id2;
   /*1. 创建线程1*/
    if(pthread_create(&thread_id1,NULL,pthread_func1,NULL))
    {
        printf("线程1创建失败!\n");
        return -1;
    }
    /*2. 创建线程2*/
    if(pthread_create(&thread_id2,NULL,pthread_func2,NULL))
    {
        printf("线程2创建失败!\n");
        return -1;
    }
    
    /*3. 等待线程结束,释放线程的资源*/
    pthread_join(thread_id1,NULL);
    pthread_join(thread_id2,NULL);
    return 0;
}
//gcc pthread_demo_code.c -lpthread

2.2 스레드 종료

프로세스가 종료될 때 종료 함수를 호출하는 것처럼 스레드는 pthread_exit 함수를 호출하여 실행을 종료합니다. 이 함수의 기능은 이를 호출하는 스레드를 종료하고 개체에 대한 포인터를 반환하는 것입니다.

이 함수의 기능은 이를 호출하는 스레드를 종료하고 객체에 대한 포인터를 반환하는 것입니다. 반환 값은 pthread_join 함수의 두 번째 매개 변수를 통해 얻을 수 있습니다.

함수 프로토타입

#include <pthread.h>
void pthread_exit(void *retval);

매개변수 분석 스레드의 반환 주소. 참고: 스레드 스택은 스레드가 끝날 때 해제되어야 합니다. 이는 스레드 함수가 종료하려면 pthread_exit()를 호출해야 함을 의미합니다. 그렇지 않으면 기본 프로세스 함수가 ​​종료될 때까지 스레드 스택이 해제되지 않습니다

2.3 스레드가 끝날 때까지 기다리세요

pthread_join() 함수, 차단 방식으로 스레드 사양을 기다리는 스레드가 종료됩니다. 함수가 반환되면 대기 중인 스레드의 리소스가 회수됩니다. 스레드가 종료되면 함수는 즉시 반환됩니다. 그리고 thread에 의해 지정된 스레드는 조인 가능(조합 속성) 속성이어야 합니다. 함수 프로토타입

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

매개변수 첫 번째 매개변수: 스레드 식별자, 즉 스레드 ID는 고유한 스레드를 식별합니다. 마지막 매개변수: 대기 스레드가 반환한 주소를 저장하는 데 사용되는 사용자 정의 포인터입니다. 반환 값 0은 성공을 나타냅니다. 실패하면 오류 번호가 반환됩니다. 스레드 반환값 수신 예:

//退出线程
pthread_exit ("线程已正常退出");
//接收线程的返回值
void *pth_join_ret1;
pthread_join( thread1, &pth_join_ret1);

2.4 스레드 분리 속성

创建一个线程默认的状态是joinable(结合属性),如果一个线程结束运行但没有调用pthread_join,则它的状态类似于进程中的Zombie Process(僵死进程),即还有一部分资源没有被回收(退出状态码),所以创建线程者应该pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于进程的wait,waitpid)。但是调用pthread_join(pthread_id)函数后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。

pthread_detach函数可以将该线程的状态设置为detached(分离状态),则该线程运行结束后会自动释放所有资源。 函数原型

#include <pthread.h>
int pthread_detach(pthread_t thread);

参数 线程标识符 返回值 0表示成功。错误返回错误码。 EINVAL线程并不是一个可接合线程。 ESRCH没有线程ID可以被发现。

2.5 获取当前线程的标识符

pthread_self函数功能是获得线程自身的ID。 函数原型

#include <pthread.h>
pthread_t pthread_self(void);

返回值 当前线程的标识符。 pthread_t的类型为unsigned long int,所以在打印的时候要使用%lu方式,否则显示结果出问题。

2.6 自动清理线程资源

线程可以安排它退出时需要调用的函数,这样的函数称为线程清理处理程序。用于程序异常退出的时候做一些善后的资源清理。 在POSIX线程API中提供了一个pthread_cleanup_push()/pthread_cleanup_pop()函数用于自动释放资源。从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用 pthread_exit()和异常终止)都将执行pthread_cleanup_push()所指定的清理函数。

注意:pthread_cleanup_push函数与pthread_cleanup_pop函数需要成对调用。 函数原型

void pthread_cleanup_push(void (*routine)(void *),void *arg); //注册清理函数
void pthread_cleanup_pop(int execute); //释放清理函数

参数 void (*routine)(void *) :处理程序的函数入口。 void *arg :传递给处理函数的形参。 int execute:执行的状态值。 0表示不调用清理函数。1表示调用清理函数。

导致清理函数调用的条件:

调用pthread_exit()函数

pthread_cleanup_pop的形参为1。 注意:return不会导致清理函数调用。

2.7 自动清理线程示例代码

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
//线程清理函数
void routine_func(void *arg)
{
   printf("线程资源清理成功\n");
}
//线程工作函数
void *start_routine(void *dev)
{
   pthread_cleanup_push(routine_func,NULL);
   //终止线程
   // pthread_exit(NULL);
    
   pthread_cleanup_pop(1); //1会导致清理函数被调用。0不会调用。
}
int main(int argc,char *argv[])
{
   pthread_t thread_id;  //存放线程的标识符
   /*1. 创建线程*/
   if(pthread_create(&thread_id,NULL,start_routine,NULL)!=0)
   {
      printf("线程创建失败!\n");
   } 
  /*2.设置线程的分离属性*/
   if(pthread_detach(thread_id)!=0)
   {
   printf("分离属性设置失败!\n");
   }
   while(1){}
   return 0;
}

2.8 线程取消函数

pthread_cancel函数为线程取消函数,用来取消同一进程中的其他线程。

头文件: #include <pthread.h>
函数原型:pthread_cancel(pthread_t tid);

相关推荐:《Linux视频教程

위 내용은 Linux 시스템 프로그래밍(pthread) 스레드 생성 및 사용에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.im에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제