C++多线程编程学习

来源:互联网 发布:苹果cms手机模板破解版 编辑:程序博客网 时间:2024/06/01 10:08

1、线程的基本概念、线程的基本状态及状态之间的关系。

(1)线程的概念 

-------1) 线程最直接的理解就是“轻量级进程”,它是一个基本的CPU执行单元,也是程序执行流的最小单位,由线程ID、程序计数器、寄存器集合和堆栈组成。 

-------2) 线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可以与同属一个进程的其它线程共享进程所拥有的全部资源。

-------3)不同的线程可以执行相同的程序,即同一个服务被不同的用户调用时,操作系统为它们创建成不同的线程。

-------4)线程是处理机的独立调度单位,多个线程是可以并发执行的。在单CPU的计算机系统中,各线程可以交替的占用CPU,在多CPU的计算机系统中,各线程可以同时占用不同的CPU,若各个CPU同时为一个进程内的各线程服务则可缩短进程的处理周期。

(2)线程的基本状态

线程也有就绪、阻塞和运行三种状态。

执行状态表示线程正在获得处理机而运行

就绪状态指线程已具备了各种执行条件,一旦获得CPU便可执行的状态

阻塞状态指线程在执行中因某事件而受阻,处于暂停执行的状态。


2、线程与进程的区别

1)调度

在传统的操作系统中,拥有资源和独立调度的基本单位都是进程。在引入线程的操作系统中,线程是独立调度的基本单位,进程是拥有资源的基本单位。在同一进程中,线程的切换不会引起进程切换。在不同的进程中进行线程切换,如从一个进程内的线程切换到另一个进程中的线程时,会引起进程切换。

2)拥有资源

不论是传统的操作系统还是拥有线程的操作系统,进程都是拥有资源的基本单位,而线程不拥有资源(只有一点必不可少的资源),但线程可以访问其隶属进程的系统资源。

3)并发性

在引入线程的操作系统中,不仅进程间可以并发执行,同一进程内的多个线程间也可以并发执行,从而使操作系统具有更好的并发性,提高了系统吞吐量。

4)系统开销

由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、IO设备等,因此操作系统所付出的开销远大于创建或撤销线程时的开销。类似的,进行进程切换时,涉及当前执行过程CPU环境的保存及新调度到进程CPU环境的设置,而线程切换只需要保存和设置少量的寄存器内容,开销很小。此外,由于同一进程内的多个线程共享进程的地址空间,因此,这些线程之间的同步与通信非常容易实现,甚至无需操作系统的干预。

5)地址空间和其它资源

进程的地址空间相互独立,同一进程的各线程共享进程的资源,而进程内的线程对其它进程不可见。

6)通信方面

进程间通信(IPC)需要进程同步和互斥手段的辅助,以保证数据的一致性,而线程间可以直接读/写进程数据段(如全局变量)来进行通信。


3、线程的同步与互斥

线程同步的方法主要有以下四种:

-------1)临界区(Critical Section):通过临界区实现多个线程对同一公共资源或一段代码的串行访问,速度快,适合控制数据的访问。    

      保证某一时刻只有一个线程访问某一资源的简便方法。任意时刻只允许一个线程对资源的访问。如果同一时刻由多个线程试图访问临界区,则其中一个线程进入临界区后,其它线程将会被挂起等待,并一直持续到该线程退出临界区。当临界区被释放后,其它线程可以抢占,并以此达到原子方式操作共享资源的目的。

      临界区的两个原语:EnterCriticalSection() 进入临界区;LeaveCriticalSection()退出临界区。

-------2)互斥量(Mutex):通过协调线程共同对一个共享资源的单独访问而设计。 

      互斥量跟临界区很相似,只有拥有互斥对象的线程才具有访问资源的权限。由于互斥对象只有一个,因此就决定了同时只有一个线程拥有对资源的访问权限。当前占据资源的线程在任务处理完成后交付互斥对象,以便其它线程可以拥有该互斥对象实现对资源的控制访问。互斥量比临界区复杂,互斥量不仅可以实现同一应用程序的不同线程间的同步,而且可以实现不同程序间线程的对资源的安全共享。

      互斥量包含的几个操作原语:

          CreateMutex()创建互斥量

          OpenMutex()打开互斥量

          ReleaseMutex()释放互斥量

          WaitForMultipleObjects() 等待互斥对象

-------3)信号量(Semaphores):可以控制有限用户对同一资源的的访问而设计;

      信号量对线程同步的方法与前几种不同,信号量允许多个线程同时使用共享资源,这与操作系统中的PV操作相同。它指出了同时访问共享资源的最大线程数目。它允许多个线程在同一时刻访问同一资源,但是限制了同一时刻访问资源的最大线程数目。在用CreateSemaphore()创建信号量时,要同时指出允许访问的最大资源基数和当前可用资源计数。一般把当前可用资源计数作为最大资源计数,即每增加一个线程对资源的访问相应的资源计数就会减一,只要当前可用资源计数是大于0的,就可以发出信号量信号。但是当前可用资源减小到小于0时,则说明当前占用资源的线程数目已经达到最大,不允许线程的继续进入,此时信号量也无法发出。当线程处理完资源后,应该离开的同时通过ReleaseSemaphore()使资源计数加1。在任何时候当前可用资源数目不可用大于最大资源数目。

       PV操作是由荷兰科学家提出的。信号量S是一个整数,当S大于等于0时,代表可给并发进程使用的资源实体,但S小于零正在等待使用共享资源的数目。

       P操作申请资源:

         (1)S减1

         (2)若S减1后仍大于等于0,则进程继续;

         (3)若S减1后小于0,则进程被阻塞后放入该信号相应的队列中,然后转入进程调度;

       V操作释放资源:

        (1)S加1操作;

        (2)若S加1后大于0,则进程继续执行;

        (3)若S加1小于等于0,则从信号量的等待队列中唤醒一个等待进程,然后再返回原进程继续执行或转入进程调度。

      信号量包含的几个操作原语:

         CreateSemphore()创建一个信号量;

         OpenSemphore()打开一个信号量;

         ReleaseSemaphore()退出一个信号量;

         WaitForSingleObject()等待一个信号量

------4)事件(Event):通过通知线程的有一些事件已经发生,从而可以启动后续的任务执行。

      事件对象也可以通过通知操作的方式保持线程同步,可以实现不同进程中的线程同步操作;

总结:

      1)互斥量与临界区的作用非常相似。但互斥量是可以命名的,也就是说可以扩进程使用,所以创建互斥所需的资源更多,所以如果为了在进程内部使用的话,可以通过临界区来提高速度上的优势,并且可以减少资源的使用。互斥量是跨进程的,一旦被创建就可以通过名字打开。 

     2)互斥量、信号量和事件都可以被跨越进程来进行进程同步数据操作,而其他的对象与数据同步操作无关,但对于进程和线程来讲,如果进程和线程在运行状态为无信号状态,在退出后为有信号状态。所以可以使用WaitForSingleObject来等待进程和线程退出。 

     3)通过互斥量可以指定资源独占的方式使用,但如果有下面一种情况,信号量就无法处理,比如一个用户购买了一份三个并发访问许可的数据可系统,可以根据用户购买的访问许可数量来决定由多少个线程/进程能同时进行数据库操作,这时候如果利用互斥量就没有办法完成请求,可以使用信号量。


4、死锁产生的原因以及如何避免死锁

   

    产生死锁的主要原因是

             1)系统资源不足

             2)进程运行推进的顺序不合适

             3)资源分配不当

    产生死锁的4个必要条件

             1)互斥条件:一个资源每次只能被一个进程使用

             2)请求与保持条件:一个进程因请求资源而被阻塞时,对已获得的资源保持不放

             3)不剥脱条件:进程已获得的资源在未使用完之前不被强行剥夺

             4)循环等待条件:若干进程之前形成一种头尾相接的循环等待资源关系

    如何避免死锁

             在系统设计进程调度等方面注意不让这四个条件成立,确定资源的合理分配算法,避免进程永久占据系统资源。