1.Pthread 并发编程(一)——深入剖析线程基本元素和状态
2.C语言多线程C多线程操作
3.linux多线程编程?
Pthread 并发编程(一)——深入剖析线程基本元素和状态
深入剖析pthread并发编程与线程基本元素与状态
在本文中,函函数我们将探讨pthread并发编程的数源基础,特别是函函数线程的基本概念和进程属性。我们将深入了解线程在内存布局的数源形式,并帮助您理解线程的函函数深刻内涵。
深入理解pthread_create与基础例子介绍
在解析pthread_create之前,数源游戏页面源码下载我们通过一个简单的函函数例子来了解pthread。我们将创建一个线程并打印"Hello world"字符串。数源
接下来,函函数我们编译上述程序。数源程序首先定义一个线程,函函数然后创建线程并执行func函数。数源当创建完成后,函函数主线程使用pthread_join阻塞自己,数源直到等待线程t执行完成,函函数主线程才会继续。
现在,让我们详细分析pthread_create的函数签名和参数。
深入理解参数thread
我们使用pthread_self获取线程ID,并通过保存线程ID地址的变量t获取线程ID。比较这两个获取的结果。
程序执行结果如下图所示。
从结果中,memchr源码我们了解到变量pthread_t t保存的是线程ID地址。参数t与线程ID之间的关系如下所示:
程序首先对t取地址,然后将其转化为long类型的指针,解引用即可得到对应地址的值,即线程ID。
深入理解参数arg
我们定义一个结构体用于保存字符信息,并创建一个结构体对象,将对象指针作为参数传递给要执行的线程函数,并在内部打印字符串内容。
程序执行结果如下所示。
可以看到,函数参数已经正确传递。
深入理解参数attr
在深入解析参数attr之前,我们了解程序内存布局。在位操作系统下,程序虚拟内存布局大致如下,从下至上依次为:只读数据/代码区、可读可写数据段、堆区、共享库映射区、程序栈区及内核内存区域。程序执行区域在栈区。resultful源码
根据内存布局示意图,简化得到单个线程执行流和大致内存布局如下(程序执行时有其栈帧及寄存器现场,图中已标识寄存器)。
当进行函数调用时,函数栈帧会从上往下生长。我们进行测试,观察栈帧最大容量。
程序执行结果如下图所示。
从结果中,我们得知在第8次申请栈内存时遇到段错误,因此判断栈空间大小约为8MB。事实上,Linux操作系统中程序栈空间默认最大为8MB。
现在,我们测试创建线程时栈大小。
程序执行结果如下图所示,创建线程时栈最大大小为8MB。
设置线程栈空间大小
如果需要大于8MB的栈空间,该如何操作?这就是我们讨论的attr。attr是一个pthread_attr_t对象,主要用于设置线程属性,包括栈大小。bkg源码下面的程序将栈空间大小设置为MB,并进行测试。
程序执行结果如下图所示。
结果表明,设置的MB栈空间大小有效,通过递归次数可以看出确实申请了如此大的空间。程序中对属性的操作如下,也是属性操作的一般流程:
自己为线程栈申请空间
通过函数pthread_attr_setstacksize设置栈空间大小后,使用程序验证新设置的栈空间。本节将介绍如何使用自定义内存空间作为线程栈。我们将使用两种方法验证这一点:
使用malloc函数申请内存空间
程序执行结果如下图所示。
结果显示,设置的栈空间大小为2MB成功了。程序主要使用pthread_attr_setstack函数设置栈低地址和空间大小。申请的内存空间内存布局如下图所示:
使用mmap系统调用在共享库空间申请内存作为栈空间
程序使用mmap系统调用在共享库空间申请内存作为栈空间,程序执行结果与前面不同,只是在申请内存方面有所变化,总体方向不变。
多个线程共享进程虚拟地址空间,我们只需为每个线程提供栈空间即可。基于此,多个线程执行流和内存布局如下图所示。fluent源码
图中展示了不同线程拥有各自的栈空间和寄存器现场,栈空间可以位于堆区或共享库映射区域。
深入理解线程状态
在pthread中,我们提供了函数pthread_cancel取消正在执行的线程。取消后,线程退出状态设置为宏定义PTHREAD_CANCELED。我们通过例子理解线程取消的过程。
程序在主线程中使用pthread_cancel取消线程执行,编译执行程序成功,程序正确执行且通过assert。我们首先不深入分析代码执行流程和函数意义。需要了解线程的基本特性。
与线程取消执行相关的属性有两个:
通常我们不会使用PTHREAD_CANCEL_ASYNCHRONOUS,因为这可能导致线程资源未释放,给系统带来灾难,如malloc申请的内存空间未释放、锁和信号量未释放,尤其是锁和信号量未释放,容易导致死锁。
有了知识基础,我们可以讨论函数细节:
创建默认状态和类型的线程执行死循环,观察是否能被取消:
程序启动线程进行死循环,程序不会终止,因为主线程等待线程结束,但线程进行死循环,且未调用取消点函数,程序不会终止取消。
更改程序,将线程取消类型设置为PTHREAD_CANCEL_ASYNCHRONOUS,再查看程序执行结果。
程序中在线程执行函数中使用pthread_setcanceltype将取消类型设置为PTHREAD_CANCEL_ASYNCHRONOUS,这样其他线程使用pthread_cancel即可立即取消线程执行。
pthread_setcanceltype函数签名与前面类似,参数含义相同。type表示设置的取消状态,有两个参数:PTHREAD_CANCEL_ENABLE和PTHREAD_CANCEL_DISABLE。oldstate表示原始线程取消状态,传入int类型指针将保存状态。
关于线程的细节还有较多内容,本文主要介绍核心内容。
栈大小程序的一个小疑惑
使用小程序测试线程栈空间大小,并打印func函数调用次数。每次调用时申请1MB栈空间变量。下面两个程序只有func函数有差异,主要区别在于:
程序输出结果一致,只打印times = 7。为什么即使后申请内存空间,打印times = 8时也只打印到7?
问题原因在于编译器在编译后的程序中如何申请内存空间。显示了func函数的汇编代码。
汇编代码显示编译器在函数开始时就申请了对应空间,因此程序被编译成汇编指令后,函数func在开始时就申请了空间,导致了结果。
总结
本文介绍了线程的基本元素和状态,重点讲解了与线程相关的属性函数,使用的主要函数如下。希望对您有所帮助!
更多内容合集可访问:github.com/Chang-LeHung...
C语言多线程C多线程操作
在C语言中,多线程操作涉及一系列关键函数和概念。首先,线程的创建是通过调用`pthread_create`函数来实现的,其原型为`int pthread_create(pthread_t* restrict tidp, const pthread_attr_t* restrict attr, void* (start_rtn)(void), void* restrict arg);`。函数接收四个参数:线程id指针、线程属性、一个返回void类型的指针函数以及该函数的形参。
线程挂起是通过`pthread_join`函数来实现线程间的同步,函数原型为`int pthread_join(pthread_t thread, void** value_ptr);`,它使得当前线程暂停运行,直到指定线程结束。线程退出则通过`pthread_exit(void* rval_ptr)`,结束并返回给调用者一个值。
获取当前线程id的函数是`pthread_t pthread_self(void)`,用于获取当前线程的标识。在资源管理方面,互斥锁和条件锁是多线程编程中的重要工具,如创建互斥锁使用`pthread_mutex_init`,销毁时用`pthread_mutex_destroy`,加锁与解锁分别用`pthread_mutex_lock`和`pthread_mutex_unlock`,条件锁的创建、销毁、信号、广播和等待则分别是`pthread_cond_init`、`pthread_cond_destroy`、`pthread_cond_signal`、`pthread_cond_broadcast`和`pthread_cond_wait`。
在Linux平台上,确保线程的正确结束至关重要。即使线程结束,其占用的资源不会自动释放,这时就需要使用`pthread_join`来获取其他线程的终止状态并释放资源。例如,`example.c`程序展示了如何创建和管理线程,而`leefeifei.c`示例则演示了如何使用互斥锁和条件锁来协调多个线程的执行。
linux多线程编程?
Linux系统中,多线编程是一种非常常见的编程模型。多线编程可以让程序在多个线程上同时运行,具有提高程序性能和优化CPU利用率的作用。下面是多线编程的基本流程:1.创建线程:使用pthread_create函数创建需要的线程,这个函数原型如下:
函数参数说明:
thread:用来存放线程ID的指针。
attr:线程属性,通常置NULL。
start_routine:线程运行的函数。
arg:传递给线程运行函数的参数。
2.运行线程:调用pthread_create函数后,程序开始运行线程,并在需要的时候通过pthread_join函数等待线程结束:
函数参数说明:
thread:需要等待的线程的ID。
retval:如果线程没有完全退出,将被存储线程的返回值。
3.终止线程:可以使用pthread_exit函数来终止线程的运行:
函数参数说明:
retval:线程的返回值。
多线编程需要注意一些问题,例如线程之间的同步问题、共享数据的安全访问等,需要使用互斥锁、条件变量等技术来避免死锁和数据不一致等问题。在编写多线程程序时,需要特别注意这些问题。
总之,Linux多线编程是一种非常常见的编程模型,它可以在多个线程上同时运行程序,提高程序性能和优化CPU利用率。但需要注意线程之间的同步问题和数据共享的安全访问等问题,以确保程序可以正确运行。