(八)C线程

1.线程为什么能弥补进程的缺点

为什么线程切换的开销很低

但是使用多线程来实现多线任务时,由于线程本质上它只是程序(进程)的一个函数,只不过线程函数

与普通函数的区别是,普通函数时单线的运行关系,而线程函数被注册为线程后,是多线并发运行。

                 

对于普通函数来说,只有相互调动时才会涉及函数间的切换,但是对于线程函数来说,只要运行时间片到了就会切换,但是不管是那种函数间的切换,进程自己函数的切换只是进程内部的事情,不涉及进程间切换, 就省去了进程间切换巨大销。

 

疑问:线程切换不一样需要开销?

刚说过,线程的切换其实就是函数间的切换,函数切换当然也需要开销,但是这些开销相比进程间切换的开销来说,已经非常小了。

 为什么线程间数据通信的开销很低

线程的本质就是函数,请问大家函数之间如果想要数据共享(通信)的话,应该怎么办?

函数间通信有两种方式:

              

是不是有了线程后,进程就不需要了?

线程是不可能完全替代掉进程的,只有在多线任务时会替代进程,但是运行新程序的时,我们还是必须创建子进程。

 

线程的本质是函数,函数运行需要内存空间,这个内存空间怎么来,事实上线程运行的内存空间就是进程的内存空间,因此线程运行时必须依赖于进程的存在,如果没有进程所提供的内存空间这个资源,线程根本无法运行。

换句话说,线程作为函数,只是进程的一个部分而已,线程是不可能脱离进程而独立存在。

 

对于进程中的所有函数来说(包括线程函数),进程中几乎所有的资源都是共享的,比如打开的文件描述,所有可以被调用的子函数,进程的当前工作目录,进程uid、gid,进程PID等等。

 线程自己独立的属性

(1)每个线程拥有自己独立的线程ID(TID)

(2)每个线程有独立的切换状态

         

(3)有自己独立的函数栈

        

(4)自己独立的错误号

       

(5)每一个线程有自己独立的信号屏蔽字和未决信号集

(6)每个线程有自己独立的tack_struct结构体

      

什么时候使用多线程和多进程

线程

        程序涉及多线任务时,使用线程。

进程

      程序涉及到运行新程序时,必须使用多进程,不过一般来说,如果不是大型软件和框架的话,我们的程序并不需要执行新程序。

2.线程控制相关的函数

线程控制函数有: pthread_create、pthread_join、 pthread_detach、pthread_cancel、pthread_exit等。   

线程函数是由谁提供的

进程控制的fork、exec等函数都是由os系统提供的,那线程函数是由谁提供的呢?

原本线程函数也可以完全由OS来实现,但是后来为了不给OS增加负担,同时也为了提高线程的灵活性,后来的线程就不在由OS提供,而是由单独的线程库来提供,不过线程库在实现时,也是调用了相应的系统API的,也就是说线程的核心实现也是离不开OS支持的。

线程库

(1)c线程函数

     由c线程库提供,注意这个c线程库并不是C标准库,而是POSIX C库的一部分

     posix的c线程库,是由美国一些标准组织制定,并有相应c语言和unix、Linux维护团队开发的。        、

(2)java、c++、c#的线程函数

    这些语言的线程库,是由这些语言的维护团队来开发的。

线程库和OS系统API的关系

    线程库函数实际上也是封住OS的相应API来实现的,如果线程库运行在Linux这边的话,线程库其实就是 通过调用Linux的clone()等系统函数实现的。

   将线程函数注册为线程时,其实就是通过调用这类系统API,然后去模拟我们的进程来实现的,正是因为是模拟进程来实现的,所以线程函数才能进程一样,一起被并发运行。

c线程控制函数

 线程库和函数手册的安装

sudo apt-get install glibc-doc :安装线程库
sudo apt-get install manpages-posix-dev:安装线程库的函数手册

pthread_create

#include <pthread.h>

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

  

需要强调的地方

  

pthread_cancel

#include <pthread.h>

int pthread_cancel(pthread_t thread);

  

pthread_exit

#include <pthread.h>

void pthread_exit(void *retval); 

  

pthread_self

#include <pthread.h>

pthread_t pthread_self(void);

  

pthread_join

#include <pthread.h>

int pthread_join(pthread_t thread, void **retval);

  

疑问:线程所用内存资源本身就是来自于进程空间,既然进程结束后,整个进程的资源都会被回收掉,次线程结束时干嘛要回收资源,等进程结束后一并回收不就得了吗? 

答:有些程序(进程)一旦运行后将会长期运行,不会结束,所以次线程在结束时必须回收资源,如果不回收,每结束一个次线程就导致一部分资源被占用,慢慢累积会使得整个进程资源越用越少,最后导致进程崩溃,所以次线程结束时,必须回收次线程资源。

pthread_detach    

#include <pthread.h>

int pthread_detach(pthread_t thread);

  

注册线程退出处理函数

可以注册进程退出处理函数,其实也可以注册线程退出处理函数,线程在退出时会自动调用,实现线程的扫尾处理

void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);

功能

  

弹栈线程退出处理函数的几种条件

  

线程的属性设置

可以设置的线程属性有,

  1. · 设置绑定属性
  2. · 设置分离属性
  3. · 设置线程堆栈属性
  4. · 设置线程调度优先级属性   等等

如果我们什么属性都不设置,那么线程使用的就是默认属性,事实上默认属性所提供的功能就已经足够我们使用了

将线程分离有两种方法:

· 调用pthread_detach函数实现
· 通过设置分离属性实现

这里介绍第二种:分离属性设置的步骤

线程的资源(数据)保护

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章