初探linux pthread多线程编程

简介:

多线程的创建,pthread_create:

1 //头文件
2   #include<pthread.h>
3 //函数声明
4   intpthread_create(/*指向线程标识符的指针*/,/*线程属性参数,通常为NULL*/,/*返回值是void类型指针的函数 */,/*运行函数的参数*/);
5 //成功返回0,失败返回错误编号。

注意:被创建的线程可能在pthread_create执行完毕之前就开始执行。

编译注意:编译时注意加上-lpthread参数,以调用静态链接库。因为pthread并非Linux系统的默认库

等待线程结束,pthread_join:

1 pthread_join(/*等待的线程标识符*/,/*传入指针,用于存储被等待线程的返回值,通常为NULL*/);

一开始以为这个函数没啥用,所以第一次写多线程没加入这个函数,结果发现用线程执行的函数没执行程序就结束了。才明白这个函数是让主线程阻塞在这个地方等待子线程结束。

如果主线程执行完,return 0,子线程都会直接结束掉,因为系统直接回收资源了。

一个简单的栗子:

01 #include<iostream>
02 #include<cstdio>
03 #include<string>
04  
05 #include<fcntl.h>
06 #include<errno.h>      //错误代码
07 #include<stdlib.h>  //exit函数
08 #include <pthread.h>   //线程库
09  
10 using namespace std;
11  
12 pthread_cond_t cond;
13 pthread_mutex_t mutex;
14 int count=0;
15 void *play(void *arg)                    //注意这个函数,返回值和参数都是void指针。
16 {
17     cout<<"child thread"<<endl;
18 }
19 int main()
20 {
21    pthread_t pid;
22     cout<<"main thread"<<endl;
23    pthread_create(&pid,NULL,play,NULL);       //创建线程
24    pthread_join(pid,NULL);                   //等待线程结束
25    return 0;
26 }

至此,简单的多线程可以写了。

 运行函数的参数传递问题:

就是pthread_create的最后一个参数。这是给运行的函数传递参数用的。

没有参数:

多好,直接给个NULL就完了。

一个参数:

可以在样例代码中看到,传入的函数的参数是一个void指针,所以pthread_create的第四个参数接受的也是一个void指针。对变量取个地址即可传入,然后在函数中重新转换回原本变量的指针类型,再解引用即可。(这里需要注意的是传入地址,线程中对变量的改变会引起原变量的改变,如果指针指向一块动态内存,一旦内存被回收,也会出现问题

多个参数:

毕竟,一个函数传入多个参数是很常见的。但是运行函数的参数只有一个void指针,所以要传入多个参数就必须想办法把它们“打包”通过那个void指针传递进去。

于是,第一种方法就是采用一个结构体,对多个变量打包传入。像单个参数一样指针转换一下,提取出变量即可。

第二种方法,使用void数组。创建一个void*[],里面保存指向你的所有参数的指针,然后把这个void*[]传递给pthread_create。

01 void*   route(void*   args)  
02 {  
03                   int*   iptr   =   ((void**)args)[0];             //注意这里,是void**,而不是void*
04                   float*   fptr   =   ((void**)args)[1];  
05                   char*   str   =   ((void**)args)[2];  
06                   printf("integer:   %d/nfloat:   %f/nstring:   %s/n",   *iptr,   *fptr,   str);  
07                   return   0;  
08 }  
09      
10 int   main(void)  
11 {  
12                   pthread_t   thr_id;  
13                   int   ival   =   1;  
14                   float   fval   =   10.0F;  
15                   char   buf[]   =   "func";  
16                   void*   arg[3]={&ival,   &fval,   buf};          //void指针数组
17                   pthread_create(&thr_id,   NULL,   route,   arg);  
18                   sleep(1);  
19 }

和第一种方法的不同之处在于args是一个void指针,但是我们要把它当作二级指针用void指针是可以指向任何地址的,args其实是指向那个arg[]数组的,我们知道数组其实就是一个指针,所以args指针的指针

但是void指针是不能解引用的,它不代表真实的变量,因为真实的变量还有变量大小,对应的指针能根据变量大小来加减,void*是没有的,也就不能做算法操作

所以代码中为了支持下标操作,把void*转换成void**

不是说了void*是没有类型的么,为啥void**能支持下标操作?

void*  是说: 这是一个指针,它指向的对象未知.
void*  是说: 这是一个指针,它指向一个void* 型的数据结构.void*是一个指针指针长度是已知的,所以也就可以支持下标操作了。

总结:

总算是能写个多线程的程序了,但是这个离会多线程还差得远,因为多线程的难度并不在于创建线程,而是在于线程的同步。

在linux中线程其实并没有专门独立开来说,实际上线程是使用轻量级进程实现的。所以linux是每个进程只有一个线程。

pthread_create和fork的区别:

fork出来的新进程和父进程是处于一种copy。是一个新的副本。但是pthread_create创建的线程却共享变量

转载请注明:旅途@KryptosX » 初探linux pthread多线程编程

目录
打赏
0
0
0
0
23
分享
相关文章
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
如何在阿里云的linux上搭建Node.js编程环境?
本指南介绍如何在阿里云Linux服务器(Ubuntu/CentOS)上搭建Node.js环境,包含两种安装方式:包管理器快速安装和NVM多版本管理。同时覆盖全局npm工具配置、应用部署示例(如Express服务)、PM2持久化运行、阿里云安全组设置及外部访问验证等步骤,助你完成开发与生产环境的搭建。
|
2月前
|
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
58 17
|
2月前
|
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
64 26
|
4月前
|
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
340 2
【JavaEE】多线程编程引入——认识Thread类
Thread类,Thread中的run方法,在编程中怎么调度多线程
Linux系统编程-(pthread)线程通信(自旋锁)
自旋锁不管是内核编程,还是应用层编程都会用到;自旋锁和互斥量类似,它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(也就叫自旋)状态。
457 1
Linux系统编程-(pthread)线程通信(条件变量)
条件变量是线程可用的一种同步机制,条件变量给多个线程提供了一个回合的场所,条件变量和互斥量一起使用,允许线程以无竞争的方式等待特定的条件发生。 条件变量本身是由互斥体保护的,线程在改变条件状态之前必须首先锁住互斥量,其他线程在获取互斥量之前就不会觉察到这种变化,因为互斥量必须锁定之后才改变条件。
211 0
Linux系统编程-(pthread)线程通信(读写锁)
**读写锁与互斥锁类似,读写锁比互斥锁有更高的并行性,读写锁特点如下:** ​ 1. 读写锁有三种状态,读模式下加锁(共享)、写模式下加锁(独占)以及不加锁。 ​ 2. 一次只有一个线程可以占有写模式下的读写锁;但是多个线程可以同时占有读模式下的读写锁。 ​ 3. 读写锁在写加锁状态时,其他试图以写状态加锁的线程都会被阻塞。读写锁在读加锁状态时,如果有线程希望以写模式加锁时,必须阻塞,直到所有线程释放锁。 ​ 4. 当读写锁以读模式加锁时,如果有线程试图以写模式对其加锁,那么读写锁会阻塞随后的读模式锁请求,以避免读锁长期占用,而写锁得不到请求。
242 0
Linux系统编程-(pthread)线程通信(信号量)
信号量的运用环境与互斥锁一样,但是信号量比互斥锁增加灵活,互斥锁只有两个状态(开锁和解锁),而信号量本质上是一个计数器,它内部有一个变量计数信号值,可以保护一个资源可以同时被1个或者2个或者3个线程同时使用,如果信号量的值只是设置1(状态只有0和1),那么和互斥锁就是一样的功能。
674 0