Linux多线程
linux多线程,看着一篇就够了!(指入门)
在学习多线程之前,为了让各位先感受多线程的厉害之处,建议先跑一下这个程序。(先保存和关闭重要的文件和程序)
//
// test.c
// thread
//
// Created by echo on 2020/12/19.
// Copyright © 2020 echo. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h> // gettimeofday sleep usleep
#include <sys/types.h> // open
#include <sys/stat.h> // open
#include <fcntl.h> // open
#include <errno.h> // error
#include <unistd.h> // close
//#include <linux/rtc.h> // rtc_commadn RTC_IRQP_SET / RTC_PIE_ON / RTC_PIE_OFF
#include <sys/ioctl.h>
typedef struct{
int a;
int b;
int sum;
} test;
#define size 4096000
void* child(void* parma){
int a = *(int*)parma;
int i = 10000;
while(i--){
void *memory = (void*)malloc(size);
//sleep(2);
};
return (void*)0;
}
int main()
{
pthread_t tid[10000];
test* tmp = (test*)malloc(sizeof(test));
tmp->a = 10;
tmp->b = 20;
for(int i = 0; i < 10000; i++){
pthread_create(&tid[i], NULL, child, &i);
}
sleep(100);
return 0;
}
请把运行机器配置,操作系统,占用留在评论区。感受一下,这个世界,是有坏人的~(不是)。
Linux系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。Linux下pthread是通过系统调用clone()来实现的。clone()是Linux所特有的系统调用,它的使用方式类似于fork()。
线程创建
int pthread_create(pthread_t * restrict tidp,const pthread_attr_t * restrict attr,
void *(* start_rm)(void *),
void *restrict arg );
函数说明:tidp参数是一个指向线程标识符的指针,当线程创建成功后,用来返回创建的线程ID;attr参数用于指定线程的属性,NULL表示使用默认属性;start_rtn参数为一个函数指针,指向线程创建后要调用的函数,这个函数也称为线程函数;arg参数指向传递给线程函数的参数。
返回值:线程创建成功则返回0,发生错误时返回错误码。
因为pthread不是Linux系统的库,所以在进行编译时要加上-lpthread,例如:
gcc filename -lpthread
线程处理函数
在代码中获得当前线程标识符的函数为:pthread_self()。
线程退出void pthread_exit(void * rval_ptr);
函数说明:rval_ptr参数是线程结束时的返回值,可由其他函数如pthread_join()来获取。
如果进程中任何一个线程调用exit()或_exit(),那么整个进程都会终止。线程的正常退出方式有线程从线程函数中返回、线程可以被另一个线程终止以及线程自己调用pthread_exit()函数。
线程等待int pthread_join(pthread_t tid, void ** rval_ptr);
在调用pthread_create()函数后,就会运行相关的线程函数了。pthread_join()是一个线程阻塞函数,调用后,则一直等待指定的线程结束才返回函数,被等待线程的资源就会被收回。
函数说明:阻塞调用函数,直到指定的线程终止。tid参数是等待退出的线程id;rval_ptr是用户定义的指针,用来存储被等待线程结束时的返回值(该参数不为NULL时)。
示例代码:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void* thread_exe(void* parma) {
int* res = (int*)parma;
printf("child tid = %ld\n", pthread_self());
return (void*)20;
}
int main() {
pthread_t tid;
int parma = 20;
int* res_join;
pthread_create(&tid, NULL, thread_exe, &parma);
int res = pthread_join(tid, (void*)res_join);
printf("the child return value = %d\n", *res_join);
return 0;
}
执行结果:
china@ubuntu:~/Desktop/codefile/test/signal/socket$ ./test
child tid = 140352593913600
the child return value = 20
线程清除
线程终止有两种情况:正常终止和非正常终止。线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退出,这是可预见的退出方式;非正常终止是线程在其他线程的干预下,或者由于自身运行错误(比如访问非法地址)而退出,这种退出方式是不可预见的。
不论是可预见的线程终止还是异常终止,都会存在资源释放的问题,如何保证线程终止时能顺利地释放自己所占用的资源,是一个必须考虑和解决的问题。
从pthread_cleanup_push的调用点到pthread_cleanip_pop之间的程序段中的终止动作(包括调用pthread_exit()和异常终止,不包括return)都将执行**pthread_cleanup_push()**所指定的清理函数。
void pthread_cleanup_push(void (* rtn)(void *), void * arg);
函数说明:将清除函数压入清除栈。rtn是清除函数,arg是清除函数的参数。
void pthread_cleanup_pop(int execute);
函数说明:将清除函数弹出清除栈。执行到pthread_cleanup_pop()时,参数execute决定是否在弹出清除函数的同时执行该函数,execute非0时,执行;execute为0时,不执行。
int pthread_cancel(pthread_t thread);
函数说明:取消线程,该函数在其他线程中调用,用来强行杀死指定的线程。
//
// test.c
// thread
//
// Created by echo on 2020/12/19.
// Copyright © 2020 echo. All rights reserved.
//
#include "test.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* child_1(void* parma){
printf("Im tid = %d\n",pthread_self());
return (void*)0;
}
void* child_2(void* parma){
printf("Im tid = %d\n",pthread_self());
return (void*)0;
}
int main()
{
pthread_t tid_1,tid_2;
int * tid_parma = 10;
pthread_create(&tid_1, NULL, child_1, &tid_parma);
pthread_create(&tid_2, NULL, child_2, &tid_parma);
pthread_join(