
概述在多线程应用程序中当多个线程同时运行时便产生了线程同步的需求。本课程将阐述线程同步的必要性并讲解如何使用信号量和互斥锁作为线程同步机制。在练习部分我们将重点介绍两种常见的线程同步问题并展示如何使用信号量和互斥锁来解决这些问题。目标理解线程同步机制的需求学习信号量和互斥锁的基本属性通过动手练习掌握如何使用信号量和互斥锁进行线程同步线程同步在多线程应用程序中存在多个线程同时运行的情况。如果超过一个线程试图同时访问同一资源(变量、数据结构等)通常这被称之为关键区段这可能会导致出现意外或错误的行为。这正是需要实现线程同步的地方;它是一种机制旨在确保在任何给定时刻只有一条线程执行关键区段实现线程同步的两个机制是信号量或互斥锁。它们具有一些不同的特性但本质上都属于在临界区前后由线程进行更改的变量以确保其他线程无法先于该线程完成该段代码的执行。主要区别在于信号量拥有一个在初始化时设定的最大值而互斥锁则具有所有权属性即只有增加其值的线程才能减少其值直至降至零时将其释放。在接下来的章节中我们将更详细地探讨信号量和互斥锁这两种机制包括其属性列表及可视化展示。此外还需完成两项练习以实践如何将信号量和互斥锁作为三种同步机制加以运用。信号量最简单的形式下信号量仅是一个普通的变量它会发生变化用以指示共享资源的当前状态。信号量可以被视作一种资源共享机制其中你拥有一种有限的资源实例而你需要管理该资源对多个线程的访问。它更多地是一种用于控制对特定数量资源实例访问的信号机制。信号量具有以下特性:在初始化时您设置一个初始计数(大于或等于0)和一个最大限制。“Give”将递增信号量计数除非计数已达到最大限制在这种情况下信号不会递增。Givee”可以在任何线程或ISR中执行。-“Take” 操作会减少信号量计数除非该信号量不可用(计数值为零)。任何试图获取一个不可用信号量的线程都需要等待直至有其他线程使其变为可用(即释放该信号量)。“Take” 操作只能在线程中进行而不可在中断服务例程(ISR)中执行(尽管内核确实允许ISR获取信号量但ISR不得尝试在信号量不可用的情况下进行等待)获取信号量的线程不具备优先级继承资格因为获取线程并不拥有该信号量而其他任何线程都可以释放该信号量。下图显示了信号旗的属性互斥锁与信号量不同互斥锁只能处于两种状态通常被称为“锁定”或“解锁”。此外互斥锁具有所有权属性即只有锁定该互斥锁的线程才能将其解锁。可以将其视为一种带有单一钥匙的锁定/解锁机制其中线程希望获取对某个对象的访问权。例如一段代码或一项资源需要首先获取对未锁定互斥锁的访问权然后锁定它接着才能访问该对象。如果尝试获取互斥锁的线程发现该互斥锁已被锁定那么该线程会被阻塞并需等待锁定该互斥锁的线程将其解锁。互斥锁的一种典型用途是保护代码中的关键部分该部分可由多个线程访问。关键部分是一段代码它需要在不受其他线程干扰的情况下完成否则该关键部分内的全局/静态数据可能会遭到误读或损坏。互斥锁具有以下属性:锁定一个互斥锁会递增锁定计数。递归锁定(可重入锁定)并不会使进行锁定的线程陷入阻塞状态因为该线程已经持有了互斥锁。线程应确保它解锁互斥锁的次数与锁定时的次数相同从而释放互斥锁以便其他线程能够尝试获取它。解锁一个互斥锁会减少锁定计数。当锁定计数为零时意味着该互斥锁处于未锁定状态。只有当互斥锁处于未锁定状态时线程才能尝试获取其所有权。解锁一个互斥锁会减少锁定计数。当锁定计数为零时意味着该互斥锁处于未锁定状态。只有当互斥锁处于未锁定状态时线程才能尝试获取其所有权。只有锁定互斥锁的线程才能解锁它。互斥锁的锁定和解锁只能在线程中进行而不能在ISR中执行。这是因为ISR无法参与调度器的所有权和优先级继承机制。锁定互斥锁的线程有资格继承优先级因为只有该线程才能解锁互斥锁。下图显示了互斥属性练习信号量