当前位置:   article > 正文

进程、线程与程序傻傻分不清?一文带你吃透_进程线程程序

进程线程程序

一、程序、进程、线程

在这里插入图片描述

  • 程序:程序是数据和指令的集合, 是一个静态的概念, 就是一堆代码, 可以长时间的保存在系统中
  • 进程:是程序运行的过程, 是一个动态的概念, 进程存在着生命周期, 也就是说进程会随着程序的终止而销毁, 不会永久存在系统中
  • 线程:是进程的一条流水线, 只用来执行程序,而不涉及到申请资源, 是程序的实际执行者最小的执行单元

二、 进程VS线程

我们打开一个聊天软件,这就是开启了一个进程
当我们在软件里面打开一些功能,比如空间, 扫一扫, 设置…,这些操作就是线程
所以可以说 “进程” 包含 “线程”, “线程” 是 “进程” 的子集

  1. 调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
  2. 拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源(寄存器、堆栈、上下文)。
  3. 并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
  4. 私有属性:线程有自己的私有属性TCB,线程id,寄存器、硬件上下文,而进程也有自己的私有属性进程控制块PCB,这些私有属性是不被共享的,用来标示一个进程或一个线程的标志。

三、为什么引入线程

  • 进程之间是相互独立的,比如我们使用fork其子进程与父进程代码段是共享,不过数据段、堆栈段等非共享,不可相互访问。
  • 对于进程之间数据独立,所以需要通过管道、消息队列等等机制来完成信息交换,这样相对比较浪费时间,且操作麻烦,而线程之间是共享的,所以线程之间的数据交互并不需要像进程之间那么复杂就可以完成交互,比如直接访问变量。
  • 同时在进程切换的过程中需要维护自己的页表项,即重新映射虚拟地址与物理地址等,而线程之间的切换则不需要更新页表项等,开销就大大降低,同时仿佛的进程切换对于CPU缓存也是不友好的,影响程序执行效率。

线程带来的好处

  • 一个进程中可以同时存在多个线程
  • 让进程具备多任务并行处理能力
  • 同进程下的各个线程之间可以共享进程资源 (同进程内的多线程通信十分简单高效)
  • 更轻量与高效

线程带来的坏处有

  • 因为进程资源共享,所以会产生资源竞争,需要通过锁机制来协同
  • 当进程中的一个线程奔溃时,会导致其所属进程的所有线程奔溃(一般游戏的用户设计不会采用多线程方式)

四、相关函数


 1. pthread_create

**原型**
#include <pthread.h>           
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
**功能**
	凡是使用pthread_create注册的线程,都是次线程,次线程会和主线程一起并发运行。
谁是主线程?
	main函数的那条线就是主线程,如果一个次线程都没有创建的话,整个进程就只有一个主线程,这个主线程也是整个进程。
**参数**
	thread:存放线程的TID。
	attr:用于设置线程属性,设置线程属性的目的是为了实现某些特殊功能,如果设置为NULL,表示不设置特有的属性,使用线程默认属性所提供的功能即可。正常情况下,线程默认属性所提供的功能就已经够用了,所以这个参数我们都是设置为NULL。
	start_routine:要注册为线程的函数地址
函数类型为void *(*) (void *),pthread_create它会把这个函数注册为线程,如果不注册,线程函数就是一个普通的函数。
线程函数需要我们自己定义,比如:
	void *pth_fun(void *pth_arg)
	{
	    ...//线程要做的事情
	}
	pth_fun和pth_arg的命名由自己决定。
	arg:传递给线程函数的参数,这个参数会传递给pth_arg,如果参数很多的话,我们做成一个结构体,然后把结构体变量的地址传过去。如果你不想传递参数的话,你可以设置为NULL**返回值**
	成功返回0,失败返回非零错误号。

 1. pthread_cancel

**原型**
	#include <pthread.h>                 
	int pthread_cancel(pthread_t thread); 
**功能**
	当次线程是死循环时,可以调动这个函数主动取消次线程。
**参数**
	thread:要取消线程的TID
	返回值
	成功返回0,失败返回非零错误号。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

五、示例程序

void print_fn(const char* s) {
    pid_t pid;
    pthread_t tid;
    pid = getpid();//进程id
    tid = pthread_self();//线程id
    printf("%s pid %u ,and tid %u\n", s, (unsigned int)pid, (unsigned int)tid);
}

void* new_pthread(void* arg) {
    print_fn("I am a new pthread: ");
    return NULL;
}

//一个进程 多个线程
void pthreadtest()
{
    pthread_t tid;
    int err;
    err = pthread_create(&tid, NULL, new_pthread, NULL);
    if (err != 0)
    {
    	printf("occurs error while create new pthread: %s\n", strerror(err));
    }     
    print_fn("Main thread: ");
    pthread_join(tid, NULL); //阻塞等待tid为thread的次线程结束
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/800604
推荐阅读
相关标签
  

闽ICP备14008679号