线程概念及其一些函数

线程(轻量级进程(LWP))的概念:

线程就是一个执行流,创建一个线程就相当于在内核当中创建一个PCB(task_struct),创建出来的PCB当中的内存指针是指向进程的虚拟地址空间的。

多线程的概念:

由于多个线程就是多个执行流,在多核CPU的机器当中,同一时间,每一个执行流理论上都可以拥有一个CPU,然后并行的去运行,多线程可以提高运行的效率。

线程的概念是c库当中的概念,因为线程的接口都是c库提供的。底层调用clone接口

在task_struct当中变量pid指的是线程id,对于进程号来说,是在tgid当中保存的

tgid(thread group ID) 线程组id, 进程号

pid (process ID):轻量级进程ID,线程ID

如果当前的程序当中只有一个主线程(执行main函数的线程) tgid==pid

如果当前程序当中有多个线程,主线程的PCB当中,tgid==pid

工作线程PCB中,线程会有自己的pid ,但tgid是一样的

线程的优点:

  1. 创建一个线程的开销要比创建一个进程的开销小
  2. 创建一个线程所用的资源要比进程小
  3. 进程当中的不同线程可以并行的运行
  4. 多线程序可以提高程序的运行效率

线程缺点:

  1. 健壮性/鲁棒性低
  2. 多线程的程序当中有多个执行流,一旦一个执行流异常,会导致整个进程异常。
  3. 缺乏访问控制
  4. 编程难度高,多个执行流可以并发的执行,并发执行的时候,可能会访问同一个临界资源,我们需要对访问临界资源的顺序进行控制,防止程序产生二义性的结果。
  5. 性能损失:线程在调度的时候是有开销的(上下文信息,程序计数器),如果大量的进程,会导致程序在频繁的切换,占用CPU去执行

线程的独有和共享:

独有:

  1. pid,线程ID
  2. 信号屏蔽字
  3. 调度优先级
  4. errno
  5. 一组寄存器
  6. ........

共享:

  1. 进程虚拟地址空间
  2. 文件描述符表
  3. 当前进程的工作路径
  4. 用户ID和用户组ID
  5. .........

进程与线程概念的区分

进程为应用程序的运行实例,是应用程序的一次动态执行。进程是由进程控制块、程序段、数据段3部分组成。

一个进程可以包含若干线程,使用线程可以实现应用程序同时做几件事并且互相不干扰。进程是操作系统进行资源分配的单位。线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源。线程与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一进程中的多个线程之间可以并发执行。多个线程则共享进程的数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文。多线程主要是为了利用CPU时间,同时在一个进程内运行多个任务。

多线程和多进程的区别

多进程:每一个进程都用自己独立的虚拟地址空间,这个也是进程独立性的原因。一个进程的崩溃,不会导致另外一个进程受到影响。多进程的程序也可以提高程序运行效率(本质也是增加执行流),但是带来了进程间通信的问题。

多线程:每一个进程当中的执行流都是共用一个虚拟地址空间,所以,一个执行流的异常会导致整个程序的退出。多线程的程序也是可以提高运行效率,但是会导致程序健壮性低,代码编写复杂。


线程控制

线程创建,线程终止、线程等待、线程分离

注:线程控制当中的接口都是库函数,使用线程控制的接口需要链接线程库,线程库的名称叫做pthread 链接的时候增加lpthread

线程创建:

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

thread:线程标识符

  注:和线程id并不是一回事, 是线程独有空间的首地址,通过这个标识符可以对当前的线程进行操作,调用pthread_create作为出参返回

attr:线程属性(栈的大小、栈的起始位置、分离属性、优先级调度属性等)

pthread_attr_t是一个结构体,这个结构体完成对新创建线程属性的设置;如果说,创建线程的时候,该参数被设置为NULL,则认为采用默认的属性

start_routine : 线程入口函数,接收一个函数的地址,这个函数返回值类型void*参数类型 void*

arg:给线程入口函数传递的参数的值

注:线程入口函数

  • 不能传递临时变量
  • 可以传递在堆上开辟的内存
  • void* 可传递任意类型,包含自定义的数据结构,类实例化的指针对象。

(可以传递一个堆上开辟的内存到线程入口函数当中去使用、但需要在线程入口函数结束的时候,将在堆上开辟的内存释放掉)


获取当前线程的线程标识符:

pthread_t   pthread_self(void) 

线程终止:

1.从入口函数的return返回

2, int pthread_cancel(pthread_t thread);

结束指定的线程

注:可以结束任一的线程,只要知道线程的一个线程标识符就可以了

thread:线程的标识符

3.void pthread_exit(void *retval) : 谁调用谁退出

retval:当前线程的退出信息,也可以传NULL

当主线程调用pthread_exit退出的时候,进程是不会退出的,而且主线程变成了Z也可以认为线程变成了一个“僵尸线程”,工作线程的状态还是R/S

原因: 线程在默认创建的时候,默认属性当中被认为joinable的

joinable:当线程退出的时候,需要其他线程来回收该线程的资源,如果没有线程回收,则在共享区中,对于退出线程的空间还是保留的,退出线程的资源没有被释放,也就造成了内存泄漏

线程等待:

注:线程等待是为了释放退出线程的资源,防止内存泄漏

int pthread_join(pthread_t thread, void **retval) 阻塞接口

pthread_t:需要等待哪一个线程,传入等待线程的标识符

如果retval不为NULL,则pthread_join()将目标线程的退出状态(目标线程提供给pthread_exit(3)的值)复制到* retval指向的位置。 如果目标线程已取消,则将PTHREAD_CANCELED放在* retval中。

return:获取入口函数return返回的内容

pthread_exit:获取pthread_exit(void*)的参数

pthread_cancel:获取到一个常数,PTHREAD_CANCELED

线程分离:

改变线程的joinable属性,变成detach,从而在线程退出的时候,不需要其他线程来回收该线程的资源

int pthread_detach(pthread_t thread);

发布了52 篇原创文章 · 获赞 6 · 访问量 1346

猜你喜欢

转载自blog.csdn.net/weixin_43519514/article/details/105344945