Linux线程的创建
这里讲POSIX线程的Linux实现,使用的NPTL线程库
-
基本概念:
- 一个进程中至少含有一个主线程(这个是默认的,不需要程序员手动创建),同一个进程中可以创建多个子线程,这些子线程共享进程的地址空间
- 需要注意的是:进程之间创建者进程称为父进程,被创建的进程称为子进程;进程中默认的线程称为主线程,其它统称都叫子线程!
- 更详细的进程与线程的对比:https://blog.csdn.net/weixin_48617416/article/details/120346554
-
线程的创建
#include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
参数1:线程id,用于标识线程的
参数2:线程的属性,一般默认为NULL
参数3:函数指针,指向的是线程的处理函数
参数4:线程处理函数的参数
返回值:成功返回0, 失败返回错误码
-
线程的等待(回收子线程的资源)
int pthread_join(pthread_t thread, void **retval);
参数1:需要等待的子线程的线程id
参数2:捕获子线程的退出码
返回值:成功返回0, 失败返回错误码
注意:同一进程内,主线程可以等待任意子线程,子线程之间除了主线程以外可以互相等待
-
线程的退出
void pthread_exit(void *retval);
参数:子线程的退出码
-
代码示例1(gcc编译的时候需要加 -pthread或者-lpthread)
#include <stdio.h> #include <string.h> #include <pthread.h> void *threadFunc(void* p) { printf("child thread\n"); //线程库的退出函数, 尽量不要使用return pthread_exit(NULL); } int main(int argc, char **argv) { int ret = 0; pthread_t thid; //创建线程, 成功返回0,失败返回错误码 ret = pthread_create(&thid, NULL, threadFunc, NULL); if(0 != ret){ printf("pthread_create: %s\n", strerror(ret)); } printf("main thread\n"); //线程等待函数, 回收线程的相关资源 ret = pthread_join(thid, NULL); if(0 != ret){ printf("pthread_join: %s\n", strerror(ret)); } return 0; }
gcc xx.c -pthread //运行结果: main thread child thread
-
代码示例2
#include <stdio.h> #include <string.h> #include <pthread.h> void *threadFunc(void* p) { printf("child thread\n"); //线程库的退出函数, 尽量不要使用return long val = 9; //子线程采用值传递方式退出栈空间val的值为9, //需要注意这个值是long类型是最好的方式,64位系统中long和指针都占8位, //可以有效避免代码产生warning, //当然也可以传递堆空间等指针出去,但是需要注意的是 //不太建议传递堆空间或者锁等指针出去,防止在其他线程内忘记回收堆空间或者忘记解锁等! pthread_exit((void*)val); } int main(int argc, char **argv) { int ret = 0; pthread_t thid; //创建线程, 成功返回0,失败返回错误码 ret = pthread_create(&thid, NULL, threadFunc, NULL); if(0 != ret){ printf("pthread_create: %s\n", strerror(ret)); } printf("main thread\n"); long retVal = 0; //线程等待函数, 回收线程的相关资源, 捕获子线程的退出码 ret = pthread_join(thid, (void**)&retVal); if(0 != ret){ printf("pthread_join: %s\n", strerror(ret)); } printf("child thread exit val = %ld\n", retVal); return 0; } //运行结果 main thread child thread child thread exit val = 9
-
代码示例3
#include <stdio.h> #include <string.h> #include <pthread.h> void *threadFunc(void* p) { //接收主线程传过来的值 long num = (long)p; printf("child num = %ld\n", num); //线程库的退出函数, 尽量不要使用return long val = 9; //子线程采用值传递方式退出栈空间val的值为9, //需要注意这个值是long类型是最好的方式,64位系统中long和指针都占8位, //可以有效避免代码产生warning, //当然也可以传递堆空间等指针出去,但是需要注意的是 //不太建议传递堆空间或者锁等指针出去,防止在其他线程内忘记回收堆空间或者忘记解锁等! pthread_exit((void*)val); } int main(int argc, char **argv) { int ret = 0; pthread_t thid; long num = 2; //给子线程采用值传递的方式传递num ret = pthread_create(&thid, NULL, threadFunc, (void*)num); if(0 != ret){ printf("pthread_create: %s\n", strerror(ret)); } printf("main thread\n"); long retVal = 0; //线程等待函数, 回收线程的相关资源, 捕获子线程的退出码 ret = pthread_join(thid, (void**)&retVal); if(0 != ret){ printf("pthread_join: %s\n", strerror(ret)); } printf("child thread exit val = %ld\n", retVal); return 0; } //运行结果 main thread child num = 2 child thread exit val = 9
-
代码示例4
#include <stdio.h> #include <string.h> #include <pthread.h> void *threadFunc(void* p) { printf("child thread\n"); pthread_exit(NULL); } int main(int argc, char **argv) { int ret = 0; pthread_t thid1, thid2; //创建线程1 ret = pthread_create(&thid1, NULL, threadFunc, NULL); if(0 != ret){ printf("pthread_create1: %s\n", strerror(ret)); } //创建线程2,需要注意哦,有靓仔看到这里写的是与上面同一个线程处理函数 //就认为是一个线程。这里是两个线程哦,只不过线程的功能是一样的, //线程处理函数你可以理解就是线程的功能,很显然线程的功能可以相同! ret = pthread_create(&thid2, NULL, threadFunc, NULL); if(0 != ret){ printf("pthread_create2: %s\n", strerror(ret)); } printf("main thread\n"); //注意,每一个线程都需要回收哦 ret = pthread_join(thid1, NULL); if(0 != ret){ printf("pthread_join1: %s\n", strerror(ret)); } ret = pthread_join(thid2, NULL); if(0 != ret){ printf("pthread_join2: %s\n", strerror(ret)); } return 0; } //运行结果 main thread child thread child thread
-
代码示例5
#include <stdio.h> #include <string.h> #include <pthread.h> void *threadFunc(void* p) { //子线程接收主线程传递过来的值 long num = (long)p; printf("child num = %ld\n", num); //修改num值,当成退出码传递出去给主线程 num = 10; pthread_exit((void*)num); } int main(int argc, char **argv) { int ret = 0; pthread_t thid1, thid2; long num = 2; //创建线程1 ret = pthread_create(&thid1, NULL, threadFunc, (void*)num); if(0 != ret){ printf("pthread_create1: %s\n", strerror(ret)); } num += 1; //创建线程2,需要注意哦,有靓仔看到这里写的是与上面同一个线程处理函数 //就认为是一个线程。这里是两个线程哦,只不过线程的功能是一样的, //线程处理函数你可以理解就是线程的功能,很显然线程的功能可以相同! ret = pthread_create(&thid2, NULL, threadFunc, (void*)num); if(0 != ret){ printf("pthread_create2: %s\n", strerror(ret)); } printf("main thread\n"); //注意,每一个线程都需要回收哦 ret = pthread_join(thid1, NULL); if(0 != ret){ printf("pthread_join1: %s\n", strerror(ret)); } //接收子线程2的退出码 long retVal = 0; ret = pthread_join(thid2, (void**)&retVal); if(0 != ret){ printf("pthread_join2: %s\n", strerror(ret)); } //通过这个打印你会清晰的看到这是值传递,子线程中的修改不会影响主线程的num值 printf("main num = %ld, retVal = %ld\n", num, retVal); return 0; } //运行结果 main thread child num = 3 child num = 2 main num = 3, retVal = 10
以上就是线程的一些基本使用方式,本人能力有限,如有错误望各位大佬不吝指正,原创不易,转载请注明出处!