POSIX线程(一)linux线程概述、线程基础函数(pthread_create、exit、join)

线程概述

栗子:
有一家大工厂,有很多个厂房,每一个厂房都可以独立工作,多个厂房则效率更高。厂商根据市场需求调整要开几间厂房进行生产,如果需求不高,就保存一间厂房生产即可,需求高就多开几间。
这里:
一个厂房——一个进程
一个厂房里面的一个工序——线程


进程是操作系统中的一个基本单元,我们整个系统是由无数个进程组成
线程是操作系统运行的最小单元,每一个进程如果不做处理,默认就有一个线程,叫主线程
一个进程如果有多个线程,则除了主线程之外其他线程叫副线程

进程是资源分配的基本单位,线程是调度的基本单位
在这里插入图片描述

在linux中,内核把线程和进程一样来管理,线程是轻量级进程,内核只认识pcb

来源:linux线程的创建与使用


下面介绍一些linux下线程的特性,并与进程区别

  • linux支持多线程,一个进程可以拥有多个线程,多线程是除了多进程外另一种并发方式
  • 各个进程之间有父子或兄弟关系,各个副线程之间没有父子关系,线程只有主从关系
  • 主线程和副线程共享:.text段,.bss段 .data段, 堆,动态库加载区。不共享:栈不共享(如果创建5个线程的话,这5个线程平均分配这个栈)
  • 进程间通讯必须经过操作系统,而线程间通讯不必经过操作系统,线程间通信是通过:堆和全局变量。
  • 线程的优点:创建代价小,线程见切换比进程间切换方便,线程占用资源比进程少
  • 线程的缺点:共享变量操作过程中造成的不确定性,要考虑互斥量文件锁等操作,多线程难以调试
  • 多线程环境中,主线程终止,全部子线程被迫终止(没有了资源),这一点不像僵尸进程或者孤儿进程
    更多线程理论概念可参考
    Linux-线程学习(上)

线程标识符pthread_t:

  • 像每个进程有一个进程ID一样,每个线程也有一个线程ID
  • 进程ID在整个系统中是唯一的,但线程不同,线程ID只在它所属的进程环境中有效
  • 线程ID用pthread_t数据类型来表示,实现的时候可以用一个结构来代表pthread_t数据类型,所以可以移植的操作系统不能把它作为整数处理

实战注意事项

  • 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
  • 要使用这些函数库,要通过引入头文件<pthread.h>
  • 链接这些线程函数库时要使用编译器命令的“-lpthread”选项
    在vs+visualGDB下增加pthread编译方法:
    注意:每次新建工程都要记得配置,必须选定一个工程再点GDB选项才有反应不然选项弹窗不会弹出!
    在这里插入图片描述

在ubuntu+codeblock下增加pthread编译方法:
在这里插入图片描述

线程系统函数

pthread_create

作用:创建一个新的线程

int  pthread_create(pthread_t *thread,
			pthread_attr_t *attr,
			void*(*start_routine)(void*),
			void *arg);

• thread:新线程创建成功后,保存新线程的标识符
• attr:设置线程的属性,一般不需要什么特殊的属性,直接传 NULL即可

Posix线程中的线程属性pthread_attr_t主要包括detach属性、policy属性、优先级、继承属性、堆栈地址、scope属性、堆栈大小。在pthread_create中,把第二个参数设置为NULL的话,将采用默认的属性配置。
typedef unsigned long int pthread_t;
在/usr/include/i386-linux-gnu/bits/pthreadtypes.h定义的
joinable状态和unjoinable状态,如果线程是joinable状态,当线程函数自己返回退出时或pthread_exit时都不会释放线程所占用堆栈和线程描述符(总计8K多)。只有当你调用了pthread_join之后这些资源才会被释放。若是unjoinable状态的线程,这些资源在线程函数退出时或pthread_exit时自动会被释放。

• start_routine: 是个函数地址,线程启动后要执行的函数
• arg:传给线程启动函数的参数
返回值:成功返回0,失败返回 错误码

pthread_exit

作用:结束调用了这个函数的线程

void pthread_exit (void *retbal);

返回值:返回一个指向某个对象的指针。

  • 绝不要用它返回一个指向一个局部变量的指针
  • 线程在结束时必须调用pthread_exit函数,这与一个进程在结束时要调用exit函数是同样的道理

pthread_join

作用:在线程结束后把它们归并到一起,pthread_join相当于进程用来等待子进程的wait函数

int pthread_join(pthread_t th, void **thread_return);
  • th: 指定了将要等待的线程标识符
  • thread_return: 它指向另外一个指针,而后者指向线程的返回值

返回值:
成功时返回“0”,失败时返回一个错误代码

更多函数:可见
linux线程的创建与使用

代码实例

代码功能:
1、创建线程,传输参数stu_info,并在副线程打印出来
2、采用全局变量global_number在主线程和副线程都打印,验证共享数据
3、注释和不注释pthread_join,验证同时运行和先后运行现象
代码如下:

#include <iostream>
#include <pthread.h>//pthread_create
#include <stdio.h>//perror
#include <unistd.h>//sleep
using namespace std;

int global_number = 10;

typedef struct
{
	int id;
}STU;

void *thread_fun(void *data)//data获得pthread_create的第四个参数传的数据
{
	STU *stu_info = (STU*)data;
	cout << "stu_info" << stu_info->id << endl;
	for(int i=0;i<5;i++)
	{
		global_number++;
		cout << "thread runnning..." << global_number<<endl;
		sleep(1);
	}
}

int main(int argc, char *argv[])
{
	pthread_t pthread_id;
	STU stu_info;
	stu_info.id = 1001;
	
	if (pthread_create(&pthread_id, NULL, thread_fun, &stu_info) < 0)//2指定线程属性3函数指针4给线程传递的参数
	{
		perror("pthread create err:");
	}
	//线程合并,类似于wait
	//pthread_join(pthread_id,NULL);
	for (int i = 0; i < 5; i++)
	{
		global_number++;
		cout << "main  runnning..." << global_number<< endl;
		sleep(1);
	}
	return 0;
}

首先我们不加pthread_join,让主线程和副线程同时对全局number++,观察输出
在这里插入图片描述
可以看到:
1、确实可以通过pthread_create第四个参数传参,打印出了1001
2、主线程和副线程交替进行,共同对number++

现在我们加上pthread_join,让主线程等待副线程运行结束再往下运行,观察输出
在这里插入图片描述
可见join可控制指定线程先走,进而达到线程顺序选择的目的

end

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值