이 글은 주로 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
함수 호출은 결과를 반환합니다
질문: 절전 함수가 호출되는 이유답: 새로 생성된 스레드가 해당 스레드에 도달하기 전에 메인 스레드가 종료될 수도 있습니다. 인쇄 방법. 기본 스레드가 종료되면 모든 스레드가 종료됩니다.
2 스레드 정지때때로 스레드에 또 다른 스레드를 생성하는데, 메인 스레드는 생성된 스레드가 반환될 때까지 기다려야 하며, 그런 다음 스레드의 반환 값을 얻은 후 메인 스레드가 종료됩니다. 이때 스레드 서스펜션을 사용해야 합니다.
int pthread_join(pthread_t th, void **thr_return);。
#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);
함수 연산 결과:
4 스레드 분리
int pthread_detach(pthread_t th);
스레드를 기다리지 않고 스레드의 반환 값에 관심이 없다면 스레드를 분리된 상태로 설정하고 스레드가 종료될 때 시스템이 차지하는 리소스를 자동으로 재활용하도록 할 수 있습니다.
스레드는 분리된 상태로 변경하기 위해 pthread_detach 자체를 호출할 수 없습니다. 다른 스레드에서만 pthread_detach를 호출할 수 있습니다.
5 스레드 취소
int pthread_cancel(pthread_t 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!