운영 및 유지보수 리눅스 운영 및 유지 관리 Linux에서 C 언어로 멀티스레드 프로그래밍에 대한 자세한 소개

Linux에서 C 언어로 멀티스레드 프로그래밍에 대한 자세한 소개

Oct 14, 2017 am 11:00 AM
linux 프로그램 작성 상세한

이 글은 주로 Linux에서 C 언어로 된 멀티스레딩 프로그래밍을 소개합니다. 필요한 친구들은 참고하면 됩니다

우리는 Linux 서비스를 작성할 때 프로그램 성능을 향상시키기 위해 Linux 멀티스레딩 기술을 자주 사용합니다

약간 멀티스레딩에 대한 지식:

애플리케이션은 여러 스레드를 시작할 수 있습니다.

스레드(Lightweight Process, LWP)는 프로그램 실행의 가장 작은 단위입니다.

일반적으로 가장 간단한 프로그램에는 하나 이상의 스레드, 즉 프로그램 자체, 즉 주요 기능이 있습니다(단일 스레드 프로세스는 간단히 말해서 스레드가 하나만 있는 프로세스라고 생각하면 됩니다)

스레드 하나 차단 다른 스레드에는 영향을 미치지 않습니다.

멀티 스레드 프로세스는 시스템 CPU 리소스를 최대한 활용할 수 있습니다.

1 스레드 생성

먼저 프로세스에서 스레드를 생성하는 간단한 코드부터 시작한 다음 더 자세히 살펴보겠습니다.


#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func(void * arg)
{
 printf("func run...\n");
 return NULL;
}
int main()
{
 pthread_t t1;
 int err = pthread_create(&t1,NULL,func,NULL);
 if(err!=0)
 {
  printf("thread_create Failed:%s\n",strerror(errno));
 }else{
  printf("thread_create success\n");
 }
 sleep(1);
 return EXIT_SUCCESS;
}
int pthread_create(pthread_t *thread,const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
로그인 후 복사

메인 함수에서 위 함수를 호출하여 스레드를 생성합니다.

함수 매개변수:

첫 번째 매개변수인 pthread_t는 생성된 스레드의 고유 식별자를 나타냅니다. 이는 스레드를 생성한 후 이 구조의 포인터를 전달해야 합니다.

 두 번째 매개변수인 pthread_attr_t는 할당 스택 크기 등과 같이 이 스레드를 생성하기 위한 일부 구성을 나타냅니다. . 일반적으로 스레드 생성의 기본 구성을 나타내는 NULL을 채울 수 있습니다. 세 번째 매개변수는 함수의 주소를 나타냅니다. 스레드를 생성할 때 이 함수의 반환 값은 void*입니다. 함수의 매개변수도 void*입니다. 일반적인 형식은

void * func(void * arg){}과 같습니다. 네 번째 매개변수: 세 번째 함수를 호출하여 전달된 매개변수를 나타냅니다.

함수 반환 값:

함수는 성공적으로 0을 반환합니다. 가 0이 아닌 경우 함수 호출이 실패했음을 의미합니다. 이 경우 strerror(errno)를 사용하여 특정 오류를 인쇄할 수 있습니다.

참고: 각 스레드에는 errno의 복사본이 있고 다른 스레드에는 다른 errno가 있습니다

마지막으로 gcc를 통해 컴파일

gcc 1createthread.c -c -o 1createthread.o
gcc 1createthread.o -o thr1 -lpthread
로그인 후 복사

컴파일할 때 libpthread.so 동적 라이브러리를 연결하려면 -lpthread를 추가해야 합니다. 함수를 찾을 수 없다는 메시지가 표시됩니다

함수 호출은 결과를 반환합니다

질문: 절전 함수가 호출되는 이유답: 새로 생성된 스레드가 해당 스레드에 도달하기 전에 메인 스레드가 종료될 수도 있습니다. 인쇄 방법. 기본 스레드가 종료되면 모든 스레드가 종료됩니다.

2 스레드 정지때때로 스레드에 또 다른 스레드를 생성하는데, 메인 스레드는 생성된 스레드가 반환될 때까지 기다려야 하며, 그런 다음 스레드의 반환 값을 얻은 후 메인 스레드가 종료됩니다. 이때 스레드 서스펜션을 사용해야 합니다.

int pthread_join(pthread_t th, void **thr_return);。
로그인 후 복사

pthread_join 함수는 th로 지정된 스레드가 종료될 때까지 현재 스레드를 일시 중단하는 데 사용됩니다.

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func(void * arg)
{
 int i=0;
 for(;i<5;i++)
 {
  printf("func run%d\n",i);
  sleep(1);
 }
 int * p = (int *)malloc(sizeof(int));
 *p=11;
 return p;
}
int main()
{
 pthread_t t1,t2;
 int err = pthread_create(&t1,NULL,func,NULL);
 if(err!=0)
 {
  printf("thread_create Failed:%s\n",strerror(errno));
 }else{
  printf("thread_create success\n");
 }
 void *p=NULL;
 pthread_join(t1,&p);
 printf("线程退出:code=%d\n",*(int*)p);
 return EXIT_SUCCESS;
}
로그인 후 복사

함수 실행 결과

우리의 메인 함수는 생성된 스레드의 실행이 완료되기를 기다리고 있었고, 스레드 실행 종료의 반환값을 받았습니다

3 스레드 종료 프로세스가 () 함수를 종료하면 종료됩니다. 그러면 스레드 종료란 무엇입니까?

스레드 종료의 세 가지 상황:

스레드는 시작 함수에서 반환되며 반환 값은 스레드의 종료 코드입니다.

스레드는 동일한 프로세스의 다른 스레드에 의해 취소될 수 있습니다.

스레드가 pthread_exit를 호출합니다.

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func(void * arg)
{
 int i=0;
 while(1)
 {
  if(i==10)
  {
   int * p = (int *)malloc(sizeof(int));
   *p=11;
   pthread_exit(p);
  }
  printf("fun run %d\n",i++);
  sleep(1);
 }
 return NULL;
}
int main()
{
 pthread_t t1,t2;
 int err = pthread_create(&t1,NULL,func,NULL);
 if(err!=0)
 {
  printf("thread_create Failed:%s\n",strerror(errno));
 }else{
  printf("thread_create success\n");
 }
 void *p=NULL;
 pthread_join(t1,&p);
 printf("线程退出:code=%d",*(int*)p);
 return EXIT_SUCCESS;
}
void pthread_exit(void *arg);
로그인 후 복사

pthread_exit 함수의 매개변수는 일반 스레드가 리턴을 종료할 때와 동일하며, 종료를 기다리는 메인 스레드에 의해 획득됩니다.

함수 연산 결과:

4 스레드 분리

int pthread_detach(pthread_t th);
로그인 후 복사

pthread_detach 함수는 스레드를 분리된 상태로 만듭니다.

스레드를 기다리지 않고 스레드의 반환 값에 관심이 없다면 스레드를 분리된 상태로 설정하고 스레드가 종료될 때 시스템이 차지하는 리소스를 자동으로 재활용하도록 할 수 있습니다.

스레드는 분리된 상태로 변경하기 위해 pthread_detach 자체를 호출할 수 없습니다. 다른 스레드에서만 pthread_detach를 호출할 수 있습니다.

5 스레드 취소

int pthread_cancel(pthread_t th);
로그인 후 복사

pthread_cancel 함수를 사용하면 한 스레드가 th로 지정된 다른 스레드를 취소할 수 있습니다.

함수가 성공하면 0을 반환하고, 그렇지 않으면 0이 아닌 값을 반환합니다.

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func1(void * arg)
{
 while(1)
 {
  printf("fun run...\n");
  sleep(1);
 }
 return NULL;
}
int main()
{
 pthread_t t1;
 if(pthread_create(&t1,NULL,func1,NULL)!=0)
 {
  printf("thread_create Failed:%s\n",strerror(errno));
  return -1;
 }
 sleep(5);
 pthread_cancel(t1);
 pthread_join(t1,NULL);
 return EXIT_SUCCESS;
}
로그인 후 복사

함수 실행 결과:

上面我们说过创建一个线程函数pthread_create的第二个参数,用来决定创建线程的一些初始化状态,这里我们 举个例子,改线程一创建就是分离状态的线程(

上面介绍了pthread_detach函数的概念,可以通过pthread_attr_t在创建线程的时候就指定线程属性为detach,而不用创建以后再去修改线程属性。

先上一段代码:


#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func(void * arg)
{
 int i=0;
 for(;i<5;i++)
 {
  printf("func run%d\n",i);
  sleep(1);
 }
 int * p = (int *)malloc(sizeof(int));
 *p=11;
 return p;
}
int main()
{
 pthread_t t1;
 pthread_attr_t attr;//申明一个attr的结构体
 pthread_attr_init(&attr);//初始化结构体
 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置线程为分离线程
 int err = pthread_create(&t1,&attr,func,NULL);
 if(err!=0)
 {
  printf("thread_create Failed:%s\n",strerror(errno));
 }else{
  printf("thread_create success\n");
 }
 pthread_attr_destroy(&attr);
 pthread_join(t1,NULL);
 printf("主线程退出\n");
 return EXIT_SUCCESS;
}
로그인 후 복사

pthread_attr_t就是我们要传入的参数的结构体,一般申明的步骤有

1,申明一个pthread_attr_t对象

2,函数pthread_attr_init初始化attr结构。

3,设置线程的一些属性,比如pthread_attr_setdetachstate函数就是设置该线程创建的时候为正常状态还是分离状态。

4,函数pthread_attr_destroy释放attr内存空间

pthread_attr_setdetachstate把线程属性设置为下面两个合法值之一:

说明

PTHREAD_CREATE_DETACHED

设置线程为分离状态

PTHREAD_CREATE_JOINABLE

设置线程为正常状态

上面函数运行结果:

因为线程是个分离状态的,所以pthread_join挂起会失效,主线程很快运行结束,程序也就结束了,创建的线程还没来得及运行

线程同步

有时候我们多个线程处理订单扣减库存会遇到这样的问题,两个线程同时进入一段代码先查询库存,两个都查出来为还剩一件库存,第一个线程用掉这个库存后,将库存变为0,但是第二个线程刚才也查出来为1了,所以他还认为有库存,

这个时候操作就会引发我们想不到的意外,库存变为负数了!!所以这个时候就需要使用线程的同步!!

先上一段代码看看效果:


#include<pthread.h>
#include<stdio.h>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void * func(void * arg)
{
 int threadno =*(int*)arg;
 int i=0;
 for(;i<10;i++)
 {
  printf("%d thread%d \n",threadno,i);
  sleep(1);
 }
 return NULL;
}
int main()
{
 pthread_t t1,t2;
 int i1=1,i2=2;
 pthread_create(&t1,NULL,func,&i1);
 pthread_create(&t2,NULL,func,&i2);
 pthread_join(t1,NULL);
 pthread_join(t2,NULL);
 printf("主线程退出\n");
 return EXIT_SUCCESS;
}
로그인 후 복사

函数运行结果:

可以看到两个线程是没有规律的争相处理的,如果这段代码是扣减库存就完蛋啦!,所以我们要对这段代码进行加锁,同一时刻只能有一个线程进入操作!

先上代码:


#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void * func(void * arg)
{
 pthread_mutex_lock(&mutex);//对mutex加锁,其他线程进入后将会挂起,知道这个锁被解锁
 int threadno =*(int*)arg;
 int i=0;
 for(;i<10;i++)
 {
  printf("%d thread%d \n",threadno,i);
  sleep(1);
 }
 pthread_mutex_unlock(&mutex);
 return NULL;
}
int main()
{
 pthread_t t1,t2;
 int i1=1,i2=2;
 pthread_create(&t1,NULL,func,&i1);
 pthread_create(&t2,NULL,func,&i2);
 pthread_join(t1,NULL);
 pthread_join(t2,NULL);
 printf("主线程退出\n");
 return EXIT_SUCCESS;
}
로그인 후 복사

函数运行结果:

可以看到第二个线程先进入后一直运行结束,对mutex解锁后,第一个线程才能进方法里面运行!否则会挂起,一直等到锁被解锁!

PTHREAD_MUTEX_INITIALIZER是初始化一个快速锁的宏定义。


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
로그인 후 복사

加锁解锁函数:


int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
로그인 후 복사

总结

위 내용은 Linux에서 C 언어로 멀티스레드 프로그래밍에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 채팅 명령 및 사용 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Linux에서 Nginx를 시작하는 방법 Linux에서 Nginx를 시작하는 방법 Apr 14, 2025 pm 12:51 PM

Linux에서 Nginx를 시작하는 단계 : Nginx가 설치되어 있는지 확인하십시오. systemctl start nginx를 사용하여 nginx 서비스를 시작하십시오. SystemCTL을 사용하여 NGINX를 사용하여 시스템 시작시 NGINX의 자동 시작을 활성화하십시오. SystemCTL 상태 nginx를 사용하여 시작이 성공했는지 확인하십시오. 기본 환영 페이지를 보려면 웹 브라우저의 http : // localhost를 방문하십시오.

nginx가 시작되었는지 확인하는 방법 nginx가 시작되었는지 확인하는 방법 Apr 14, 2025 pm 01:03 PM

nginx가 시작되었는지 확인하는 방법 : 1. 명령 줄을 사용하십시오 : SystemCTL 상태 nginx (linux/unix), netstat -ano | Findstr 80 (Windows); 2. 포트 80이 열려 있는지 확인하십시오. 3. 시스템 로그에서 nginx 시작 메시지를 확인하십시오. 4. Nagios, Zabbix 및 Icinga와 같은 타사 도구를 사용하십시오.

nginx가 시작되었는지 확인하는 방법은 무엇입니까? nginx가 시작되었는지 확인하는 방법은 무엇입니까? Apr 14, 2025 pm 12:48 PM

Linux에서는 다음 명령을 사용하여 nginx가 시작되었는지 확인하십시오. SystemCTL 상태 Nginx 판사 명령 출력에 따라 : "active : running"이 표시되면 Nginx가 시작됩니다. "Active : 비활성 (죽음)"이 표시되면 Nginx가 중지됩니다.

nginx403 오류를 해결하는 방법 nginx403 오류를 해결하는 방법 Apr 14, 2025 pm 12:54 PM

서버는 요청 된 리소스에 액세스 할 수있는 권한이 없으므로 Nginx 403 오류가 발생합니다. 솔루션에는 다음이 포함됩니다. 파일 권한 확인 권한을 확인하십시오. .htaccess 구성을 확인하십시오. nginx 구성을 확인하십시오. Selinux 권한을 구성하십시오. 방화벽 규칙을 확인하십시오. 브라우저 문제, 서버 장애 또는 기타 가능한 오류와 같은 다른 원인을 해결하십시오.

Centos와 Ubuntu의 차이 Centos와 Ubuntu의 차이 Apr 14, 2025 pm 09:09 PM

Centos와 Ubuntu의 주요 차이점은 다음과 같습니다. Origin (Centos는 Red Hat, Enterprise의 경우, Ubuntu는 Debian에서 시작하여 개인의 경우), 패키지 관리 (Centos는 안정성에 중점을 둡니다. Ubuntu는 APT를 사용하여 APT를 사용합니다), 지원주기 (Ubuntu는 5 년 동안 LTS 지원을 제공합니다), 커뮤니티에 중점을 둔다 (Centos Conciors on ubuntu). 튜토리얼 및 문서), 사용 (Centos는 서버에 편향되어 있으며 Ubuntu는 서버 및 데스크탑에 적합), 다른 차이점에는 설치 단순성 (Centos는 얇음)이 포함됩니다.

Docker 원리에 대한 자세한 설명 Docker 원리에 대한 자세한 설명 Apr 14, 2025 pm 11:57 PM

Docker는 Linux 커널 기능을 사용하여 효율적이고 고립 된 응용 프로그램 실행 환경을 제공합니다. 작동 원리는 다음과 같습니다. 1. 거울은 읽기 전용 템플릿으로 사용되며, 여기에는 응용 프로그램을 실행하는 데 필요한 모든 것을 포함합니다. 2. Union 파일 시스템 (Unionfs)은 여러 파일 시스템을 스택하고 차이점 만 저장하고 공간을 절약하고 속도를 높입니다. 3. 데몬은 거울과 컨테이너를 관리하고 클라이언트는 상호 작용을 위해 사용합니다. 4. 네임 스페이스 및 CGroup은 컨테이너 격리 및 자원 제한을 구현합니다. 5. 다중 네트워크 모드는 컨테이너 상호 연결을 지원합니다. 이러한 핵심 개념을 이해 함으로써만 Docker를 더 잘 활용할 수 있습니다.

Centos는 유지 보수를 중지합니다. 2024 Centos는 유지 보수를 중지합니다. 2024 Apr 14, 2025 pm 08:39 PM

Centos는 2024 년에 상류 분포 인 RHEL 8이 종료 되었기 때문에 폐쇄 될 것입니다. 이 종료는 CentOS 8 시스템에 영향을 미쳐 업데이트를 계속받지 못하게합니다. 사용자는 마이그레이션을 계획해야하며 시스템을 안전하고 안정적으로 유지하기 위해 Centos Stream, Almalinux 및 Rocky Linux가 포함됩니다.

nginx를 시작하는 방법 nginx를 시작하는 방법 Apr 14, 2025 pm 01:06 PM

질문 : nginx를 시작하는 방법? 답변 : nginx 스타트 업 설치 nginx verification nginx is nginx 시작 다른 시작 옵션을 자동으로 시작합니다.

See all articles