当前课程知识点:基于Linux的C++ > 第十四讲 线程编程 > 14.4 线程管理(二) > LinuxCPP1404
我们看第二个例子
那我要想向这个线程里
传递一个参数怎么办
我们这里面有一个面向对象的架构了
我们定义一个类 class InfoPrinted
打印信息类
在这里面呢
有两个私有的数据字段
一个是_c 一个是_n
就是我要打印这个字符多少遍
就这个意思
有一个成员函数Show()
专门来负责打印
写了一个循环
向标准错误流里输出这个字符
搞定了 Over
我们实现线程函数PrintInfo()
传哑型指针进去
返回值是哑型指针
在这里我们的哑型传的是什么进去的呢
我们传的是那个InfoPrinted的一个对象
当然不是那个对象本身
而是指向那个对象的一个指针
所以我要把info转型成InfoPrinted的指针
在这个指针p上要用Show()
把这个信息给打印出来
这是这个线程函数要做的事情
你看那个对象的基地址
就被通过这个指针info传进来了
然后我们就可以操纵那个对象了
我们看主函数 我构造两个线程
所以要定义两个pthread_t的对象
tid1、tid2
然后我们动态构造一个
InfoPrinted类的一个对象
用p指针指向它
我们new出来的
然后调用线程创建函数
pthread_create()创建这个线程
把线程ID存到tid1里去
第二个参数传NULL
线程属性我们什么都不用管
所以第二个参数传NULL
第三个参数传线程函数PrintInfo
第四个附加参数
就是我们要传给那个线程的
参数列表中的那个附加参数
那个线程执行函数不是要带一个参数吗
那个参数从哪来吗
这就是那个回调函数的参数啊
我们前面不谈到过嘛 OK
这就是第四个参数传进去
现在这个线程被创建好之后
它就会执行
那个函数PrintInfo()
就会用第四个这个参数
作为线程函数的参数 继续
我们又构造了第二个对象
继续创建第二个线程
第一个线程负责打印字符‘a’
第二个线程负责打印字符‘z’
做完了我们return0
程序没了 结束了
你编译这程序没问题
然后你运行 你就会发现
这个程序在大部分情况下面
不会输出任何结果
你会觉得很奇怪
为啥呀 原因在这里
刚才那个程序有什么问题呢
问题就在这儿
子线程是需要使用主线程的数据的
主线程创建那两个子线程
一创建完它就结束了
它又不用等子线程执行完毕
那么当主线程结束以后
子线程想调度 它用啥数据呢
数据没了 用不了了
所以它访问不到那些数据的
那我们怎么处理这个问题呢
那么一个典型的解决方案就是
我们可以调用pthread_join()这个函数
等待子线程结束
也就是说我保证
主线程在子线程之后才结束
不就行了吗
就这个函数 pthread_join()
我就等待它
子线程没结束
我的主线程就不会结束
所以在这种情况下边
子线程就能够用到主线程的数据了
所以我们在这个函数代码里
只需要在最后添加两个函数调用
pthread_join( tid1, NULL )
pthread_join( tid2, NULL )
传递两个参数进去
调用pthread_join()等待那两个子线程结束
就OK了
在这种情况下边
主线程保证要等两个子线程都做完之后
它才会结束
所以这个时候这两个对象
主线程构造的这两个对象
p、q两个指针指向的对象
在子线程内部都可以访问到
这就是线程的函数参数
接下来的一个问题就是
线程函数的返回值
我们怎么利用起来
我这里定义一个线程函数叫IsPrime()
它用来判定一个特定的整数
是不是一个素数的
程序代码很简单了
和我们以前那个代码没什么差别
我们这里边主要是因为
参数传递和返回值都是哑型指针
所以我就必须做几个转型
除此之外和原来的代码是一样的
我们看主程序
这个程序和刚才的那个程序就不一样
我们要创建8个线程 同时来做
得到的数据肯定也有8个数据
所以结果呢
它的素性的结论
也保存在这个素性的数组里
我们启动一个for循环
创建八个线程 pthread_create()
创建它们
然后用一个循环join它们
等待那些子线程结束
这是两个循环架构
你不能把它写在一个循环架构里
如果你写在一个循环架构里
就相当于创建一个线程
然后等它结束 再创建一个
再等它结束 那就不对了
程序逻辑上就不对了
你实际上就只创建了一个线程
每次都只创建一个
都等待上一个线程死了以后
你才能创建第二个 那就不对了
所以我们现在这里边
一个for循环做完
八个线程都被创建出来了
然后八个线程就会被调度
然后接下来一个循环
我等待那八个线程全做完
就这个意思
做完了之后
这个数据就会被写到
我们的素性数组里
然后我们就可以输出这个素性数组了
你注意看输出这个素性数组
一个元素一个元素
就能够把它结果打出来
那么我们怎么
把这个结果得到的呢
那当然就在pthread_join()
这个函数调用里
我等待一个线程结束啊
那里面不传了两个参数嘛
我们刚才第一个参数传的是什么
你等待哪个线程结束
那你要传这个线程的ID
所以第一个参数传的就是线程ID
那第二个参数传的是什么呢
第二个参数其实就是
那个线程做完了以后的返回值
是那些东西啊 我们刚才没传嘛
但是现在我们需要用它
那么我们传的就是那个线程返回值
要放的地方的地址
它接受的是一个哑型指针的指针
或者严格讲起来
它是指向哑型指针的指针
明确了吧
所以是一个void**
你要把这个素性数组的
一个特定的元素 它对应第i个的线程
那么它的数据就存在第i号元里
那么把这个第i号元的入口地址
前面取个& 把它转型成void**
作为pthread_join()这个函数的
第二个参数传进去
线程一做完
它的素性结论就会给你写到这个数组里
这就是线程函数的返回值
-1.1 提纲
-1.2 程序设计的基本概念
-1.3 简单C/C++程序介绍
-1.4 程序设计的基本流程
-1.5 基本语法元素
-1.6 程序设计风格
-1.7 编程实践
-第一讲 C/C++基本语法元素--编程实践提交入口
-2.1 提纲
-2.2 结构化程序设计基础
-2.3 布尔数据
-2.4 分支结构
-2.5 break语句
-2.6 循环结构
-2.7 编程实践
-第二讲 程序控制结构--编程实践提交入口
-3.1 提纲
-3.2 函数声明、调用与定义
-3.3 函数调用栈框架
-3.4 编程实践
-第三讲 函数--编程实践提交入口
-4.1 提纲
-4.2 算法概念与特征
-4.3 算法描述
-4.4 算法设计与实现
-4.5 递归算法(一)
-4.6 递归算法(二)
-4.7 容错与计算复杂度
-4.8 编程实践
-第四讲 算法--编程实践提交入口
-5.1 提纲
-5.2 库与接口
-5.3 随机数库(一)
-5.4 随机数库(二)
-5.5 作用域与生存期
-5.6 典型软件开发流程(一)
-5.7 典型软件开发流程(二)
-5.8 编程实践
-第五讲 程序组织与开发方法--编程实践提交入口
-6.1 提纲
-6.2 字符
-6.3 数组(一)
-6.4 数组(二)
-6.5 结构体
-6.6 编程实践
-第六讲 复合数据类型--编程实践提交入口
-7.1 提纲
-7.2 指针基本概念
-7.3 指针与函数
-7.4 指针与复合数据类型(一)
-7.5 指针与复合数据类型(二)
-7.6 字符串
-7.7 动态存储管理(一)
-7.8 动态存储管理(二)
-7.9 引用
-7.10 编程实践
-第七讲 指针与引用--编程实践提交入口
-8.1 提纲
-8.2 数据抽象(一)
-8.3 数据抽象(二)
-8.4 链表(一)
-8.5 链表(二)
-8.6 链表(三)
-8.7 链表(四)
-8.8 函数指针(一)
-8.9 函数指针(二)
-8.10 抽象链表(一)
-8.11 抽象链表(二)
-8.12 编程实践
-第八讲 链表与程序抽象--编程实践提交入口
-9.1 提纲
-9.2 程序抽象与面向对象
-9.3 类类型
-9.4 对象(一)
-9.5 对象(二)
-9.6 类与对象的成员(一)
-9.7 类与对象的成员(二)
-9.8 类与对象的成员(三)
-9.9 继承(一)
-9.10 继承(二)
-9.11 继承(三)
-9.12 多态(一)
-9.13 多态(二)
-9.14 编程实践
-第九讲 类与对象--编程实践提交入口
-10.1 提纲
-10.2 四则运算符重载(一)
-10.3 四则运算符重载(二)
-10.4 关系与下标操作符重载
-10.5 赋值操作符重载(一)
-10.6 赋值操作符重载(二)
-10.7 赋值操作符重载(三)
-10.8 赋值操作符重载(四)
-10.9 赋值操作符重载(五)
-10.10 流操作符重载(一)
-10.11 流操作符重载(二)
-10.12 流操作符重载(三)
-10.13 操作符重载总结
-10.14 编程实践
-第十讲 操作符重载--编程实践提交入口
-11.1 提纲
-11.2 泛型编程概览
-11.3 异常处理机制(一)
-11.4 异常处理机制(二)
-11.5 运行期型式信息(一)
-11.6 运行期型式信息(二)
-11.7 模板与型式参数化
-11.8 题外话:术语翻译
-11.9 泛型编程实践(一)
-11.10 泛型编程实践(二)
-11.11 泛型编程实践(三)
-11.12 泛型编程实践(四)
-11.13 泛型编程实践(五)
-11.14 泛型编程实践(六)
-11.15 泛型编程实践(七)
-11.16 泛型编程实践(八)
-11.17 泛型编程实践(九)
-11.18 泛型编程实践(十)
-11.19 编程实践
-第十一讲 泛型编程--编程实践提交入口
-12.1 提纲
-12.2 程序执行环境(一)
-12.3 程序执行环境(二)
-12.4 程序执行环境(三)
-12.5 程序执行环境(四)
-12.6 输入输出(一)
-12.7 输入输出(二)
-12.8 文件系统
-12.9 设备
-12.10 库(一)
-12.11 库(二)
-12.12 makefile文件(一)
-12.13 makefile文件(二)
-12.14 makefile文件(三)
-12.15 编程实践
-第十二讲 Linux系统编程基础--编程实践提交入口
-13.01 提纲
-13.02 进程基本概念
-13.03 信号
-13.04 进程管理(一)
-13.05 进程管理(二)
-13.06 进程管理(三)
-13.07 进程间通信(一)
-13.08 进程间通信(二)
-13.09 进程间通信(三)
-13.10 进程间通信(四)
-13.11 进程池
-13.12 编程实践
-第十三讲 进程编程--编程实践提交入口
-14.1 提纲
-14.2 线程基本概念
-14.3 线程管理(一)
-14.4 线程管理(二)
-14.5 线程管理(三)
-14.6 线程管理(四)
-14.7 线程同步机制(一)
-14.8 线程同步机制(二)
-14.9 C++11线程库(一)
-14.10 C++11线程库(二)
-14.11 C++11线程库(三)
-14.12 C++11线程库(四)
-14.13 C++11线程库(五)
-14.14 编程实践
-第十四讲 线程编程--编程实践提交入口
-15.1 提纲
-15.2 Internet网络协议
-15.3 套接字(一)
-15.4 套接字(二)
-15.5 编程实践
-第十五讲 网络编程--编程实践提交入口