2024年【多线程编程学习笔记3】创建线程函数pthread_create()详解,深度剖析原理

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

/*

struct _pthread_v;

typedef struct pthread_t {
struct _pthread_v *p;
int x;
} pthread_t;
*/


2. const pthread\_attr\_t \*attr:用于手动设置新建线程的属性,例如线程的调用策略、线程所能使用的栈内存的大小等。大部分场景中,我们都不需要手动修改线程的属性,将 attr 参数赋值为 NULL,pthread\_create() 函数会采用系统默认的属性值创建线程。


pthread\_attr\_t 类型以结构体的形式定义在`<pthread.h>`头文件中,此类型的变量专门表示线程的属性。关于线程属性,您可以阅读《[Linux线程属性详解]( )》一文做详细地了解。



//pthread_attr_t 结构体定义
typedef struct pthread_attr_t pthread_attr_t;
struct pthread_attr_t
{
unsigned p_state;
void *stack;
size_t s_size;
struct sched_param param;
};


3. void \*(*start\_routine) (void *):以函数指针的方式指明新建线程需要执行的函数,该函数的参数最多有 1 个(可以省略不写),形参和返回值的类型都必须为 void* 类型。void* 类型又称空指针类型,表明指针所指数据的类型是未知的。使用此类型指针时,我们通常需要先对其进行强制类型转换,然后才能正常访问指针指向的数据。



> 
> 如果该函数有返回值,则线程执行完函数后,函数的返回值可以由 pthread\_join() 函数接收。有关 phtread\_join() 函数的用法,我们会在《[获取线程函数的返回值]( )》一节给大家做详细讲解。
> 
> 
> 


4. void \*arg:指定传递给 start\_routine 函数的实参,当不需要传递任何数据时,将 arg 赋值为 NULL 即可。


如果成功创建线程,pthread\_create() 函数返回数字 0,反之返回非零值。各个非零值都对应着不同的宏,指明创建失败的原因,常见的宏有以下几种:


* EAGAIN:系统资源不足,无法提供创建线程所需的资源。
* EINVAL:传递给 pthread\_create() 函数的 attr 参数无效。
* EPERM:传递给 pthread\_create() 函数的 attr 参数中,某些属性的设置为非法操作,程序没有相关的设置权限。



> 
> 以上这些宏都声明在 <errno.h> 头文件中,如果程序中想使用这些宏,需提前引入此头文件。
> 
> 
> 


接下来通过一个样例,给大家演示 pthread\_create() 函数的用法:



#include <stdio.h>
#include <unistd.h> //调用 sleep() 函数
#include <pthread.h> //调用 pthread_create() 函数
void *ThreadFun(void arg)
{
if (arg == NULL) {
printf(“arg is NULL\n”);
}
else {
printf(“%s\n”, (char
)arg);
}
return NULL;
}
int main()
{
int res;
char * url = “http://www.biancheng.net”;
//定义两个表示线程的变量(标识符)
pthread_t myThread1,myThread2;
//创建 myThread1 线程
res = pthread_create(&myThread1, NULL, ThreadFun, NULL);
if (res != 0) {
printf(“线程创建失败”);
return 0;
}
sleep(5); //令主线程等到 myThread1 线程执行完成

//创建 myThread2 线程
res = pthread_create(&myThread2, NULL, ThreadFun,(void*)url);
if (res != 0) {
    printf("线程创建失败");
    return 0;
}
sleep(5); // 令主线程等到 mythread2 线程执行完成
return 0;

}


![image-20210710230409718](https://img-blog.csdnimg.cn/img_convert/dbeaa1f964e8861fe4a56328d0bea862.png)


可以通过gif来看看sleep的效果


![GIF](https://img-blog.csdnimg.cn/img_convert/180798ef617dd92cccc3aaaed0664119.gif)


程序中共创建了 2 个线程,分别命名为 myThread1 和 myThread2。myThread1 和 myThread2 线程执行的都是 threadFun() 函数,不同之处在于,myThread1 线程没有给 threadFun() 函数传递任何数据,而 myThread2 线程向 threadFun() 函数传递了 “http://www.biancheng.net” 这个字符串。


从程序的执行过程不难看出, pthread\_create() 函数成功创建的线程会自动执行指定的函数,不需要手动开启。此外,为了确保创建的线程能在主线程之前执行完,程序中调用 sleep() 函数延缓了主线程的执行速度。



> 
> 您可以尝试将程序中的 sleep() 函数全部注释掉,然后重新编译、执行此程序。整个进程会随着主线程执行结束而立即终止,由于主线程执行太快,子线程可能尚未执行完就被强制终止。


![img](https://img-blog.csdnimg.cn/img_convert/4c8e883f242ad23c189f686a682c5f91.png)
![img](https://img-blog.csdnimg.cn/img_convert/8fb65437c9b4433ab9368de64f07f0f9.png)
![img](https://img-blog.csdnimg.cn/img_convert/e08ddfccbf4dc52560e46754dc0387b2.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**

系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值