第六章 Linux下的线程

第六章  Linux下的线程

   6.1线程的基本概念:

    Linux中的线程是轻量级线程(lightweight thread)。Linux的线程调度是由内核调度程序完成的,每个线程有自己的ID号。与进程相比,它们消耗的系统资源较少,创建较快,相互间的通信也较容易。存在于同一进程中的线程会共享一些信息,这些信息包括全局变量,进程指令,大部分数据,信号处理程序和信号设置,打开的文件,当前工作的目录以及用户ID和用户组ID.同时作为一个独立的线程,它们又拥有一些区别于其他线程的信息,包括线程ID,寄存器集合(如程序计数器和堆栈指针),堆栈,错误号,信号掩码以及线程优先权。

 

6.2线程的实行和创建

    Linux线程的实现包括在用户级实现和核心级实现。在用户级实现线程时,没有核心支持的多线程进程。因此,核心只有单线程进程的概念,而多线程进程由与应用程序连接的过程库实现。核心不知道线程的存在也就不能独立的调度这些线程了。线程的调度由一个线程运行库组织。如果一个线程调用了一个阻塞的系统调用,进程可能被阻塞,当然其中的所有线程也同时被阻塞,所以UNIX所有了异步I/O工具。这种机制的最大缺点是不能发挥多处理器的优势。它的优点是系统的消耗小,可以修改以适应特殊应用场合。而在核心级实现线程时,允许不同进程里的线程按照同一相对优先方法凋度,这适合于发挥多处理器的并发优点。目前Linux众多的线程库中大部分实现的是用户级的线程,只有一些用于研究的线程库才尝试实现核心级进程

    LinuxThread线程库采用称为1-1模型:每个线程实际上在核心是一个个单独的进程,核心的调度程序负责线程的调度,就像调度普通进程。线程是用系统调用clone()创建的,clone()系统调用是fork()的普通形式,它允许新进程共享父进程的存储空间,文件描述符和软中断处理程序。这种模型的优点是最小限度地依赖CPU级多处理技术(每个CPU一个线程),以及最小限度地使用I?O操作。

    系统创建线程是一个复杂的工作,当一个进程启动后,它会自动创建一个线程即主线程(main thread)或者初始化线程(initial thread),然后就利用Pthread_initialize() 初始化系统管理线程并且启动线程机制,这时完成的工作是建立管理线程堆栈以及建立管理线程通信的管道。线程机制启动后,要创建线程必须让Pthread_creat()向管理线程发送请求。管理线程接到请求后首先检查是否需要调整调度策略,如果需要,判断是否能够做到。接着为线程找出一个空段,并且根据需要再分配堆栈。接下来,分配新线程的标识符,处始化新线程描述符,确定线程的调度参数,并根据需要调整管理线程的优先级。最后便创建线程。  新线程创建以后,管理线程会将其插入系统活动线程的双向链表中。Common threads的调度和普通进程并无大的区别,创建者可以自己设定线程的优先级。但是Manage thread则需要实时响应各进程提出的请求,所以Manage thread被设置成高于其他线程的优先级,方法是在创建每个新线程是调整Manage thread的优先级。

 

  

 


6-1:线程的初始化机制及创建图

 

6.3 LinuxThreads线程库

Linux支持若干线程库,它们有些遵循Posix标准,有些不遵循。最常用的线程库是LinuxThreads,它是一个面向Linux的Posix 1003.1c pthread标准接口。此线程库实现时使用了两个信号SIGUSR1和SIGUSR2,因此用户不能使用它们。此线程库将线程分配在高端存储空间,在初始化进程的堆栈下2M处。她采用按需增长的策略,所以初始化时不会使用很多虚拟空间(现在是4k),如果需要可以增长到2M。为每个线程保留这么大的地址空间意味着,在32为体系结构下,不能有超过大约1000个线程共存,因为这是合理的,每个线程使用核心的进程表的一项,而它通常限制为512项。

 

6.4 线程间通信

    多线程编程时经常要涉及到线程间的通信或同步,一般使用两种方式解决同步问题:互斥锁和条件变量。互斥即相互排斥的锁是一种信号量,且是mutex_t类型的对象。对于一个给定的互斥锁,在同一时刻只有一个线程可对其上或者解,因此互斥锁可以防止两个线程在同一时刻访问相同的共享资源。一个进程如果试图锁住一个已经被锁定的互斥锁,那么它将被挂起直到该互斥被释放。解决同步问题的第二种方法是使用条件变量,条件变量实际上是对互斥锁的补充。互斥锁只有两个状态即锁定和释放,而在实际场合往往对应多中情况。Posix标准的条件变量下允许线程阻塞并等待另一个线程的信号,这样就弥补了两个状态的不足。当接收到一个信号时,阻塞的线程将被唤醒,并尝试获得相关的互斥锁。

线程间的同步主要有以下函数:

pthread_once()   用于初始化线程的特定数据

pthread_key_create()   用于创建线程特定数据

pthread_getspecific()   用于获取与一个键关联的值

pthread_setspedific()   用于设置与一个键关联的值

pthread_mutex_lock()   用于锁定互斥锁

pthread_mutex_unlock()   用于解开互斥锁

pthread_cond_init()   初始化条件变量

pthread_cond_wait()   对条件互斥解锁

 

6.5 守护线程分析

    Linux系统中有许多核心精灵进程,同时又叫核心线程和守护线程。这种线程运行在后台,不会在终端打印执行信息,因此不影响终端的工作。大部分守护线程在系统启动时启动,这时有些在init.c文件中的start_kernel()函数中启动如kswapd,有些在启动脚本/etc/initiab或者/etc/rc.d/rcN.d(N为运行级别号)中启动如inetd,以这中方式启动的进程具有超级用户的权限。小部分网络服务程序由inetd服务器启动,例如:可以通过inted启动nfsd.tftpd,bootbd以及dhcpd等。时钟服务器cron也可以定期按规定启动一些核心线程,我们可用at命令指定cron在何时启动何程序。最后,在用户终端上,也可随时启动和终止某些守护线程,例如可用命令“/etc/rc.d/nfsd start”启动nfsd,当然还可在终端上测试即将投入使用守护线程。

    守护线程在进行消息处理时借助于syslog()函数,该函数可以把守护线程输出的消息发送到特定的syslogd守护线程。当系统调用syslog()函数时,如果是第一次调用,则该函数会创建一个数据套接口,然后调用connect()函数连接由syslogd守护线程建立的套接口/var/run/lo。在第一次调用syslog()函数之前,也可以调用openlogd() 函数,这样守护线程在发送信息前对信息初始化,默认情况下openlog()函数创建数据套接口。

Syslog守护线程是在启动初始化脚本中启动的,它首先读入/etc/syslog.conf文件,设定守护线程如何处理各种登记消息,接下来它会将收到的消息发送到文件,扩展台,指定用户或者其他系统的syslog守护线程。Syslog守护线程启动以后就一直等待收到消息,然后读入登记消息,按照配置文件的规定处理消息。当syslog守护线程收到SIGHUP信号时就会重新读入配置文件/etc/syslog.conf

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值