Feedback
Feedback

If you are having issues with the exercises, please create a ticket on DevZone: devzone.nordicsemi.com
Drag & Drop Files, Choose Files to Upload 您最多可以上传 2 个文件。
  • 简体中文
    Eng
    简体中文
  • 练习 1 – 信号量

    信号量

    让我们看看信号量在实际中的应用。在本练习中,我们将初始化一个信号量,其计数属性将反映系统中特定资源的实例数量。将有一个消费者线程想要消耗该资源,以及一个生产者线程负责生产该资源。每当消费者线程尝试获取访问权限时,我们都会递减并打印计数值;每当生产者线程放弃对实例的访问权限时,我们都会递增并打印计数值。

    练习步骤

    1. 在本课程的 GitHub 仓库中,打开此练习的基础代码,位于 l8/l8_e1。

    2. 将生产者和消费者线程的优先级设置为相等。

    #define PRODUCER_PRIORITY        5 
    #define CONSUMER_PRIORITY        5
    C

    3. 将受限资源的实例数量初始化为 10。在本练习中,了解具体是什么资源并不重要(它可以是打印机、传真机、外设、时钟等任何东西),只需假设我们有 10 个该资源的实例。

    volatile uint32_t available_instance_count = 10;
    C

    4. 创建生产者线程,该线程仅释放资源而不进行任何检查,并休眠随机时间(0-9 毫秒)。当它从休眠中醒来时,会在循环中无限重复此步骤。

    void producer(void)
    {
    	printk("Producer thread started\n");
    	while (1) {
    		release_access();
    		k_msleep(sys_rand32_get() % 10);
    	}
    }
    C

    5. 创建消费者线程,该线程在不进行任何检查的情况下获取资源访问权限,并假设在进入随机时间(0-9 毫秒)的休眠之前已获得访问权限。当它醒来时,会在循环中无限重复此步骤。

    void consumer(void)
    {
    	printk("Consumer thread started\n");
    	while (1) {
    		get_access();
    		k_msleep(sys_rand32_get() % 10);
    	}
    }
    C

    6.1 在模拟获取资源的函数 get_access() 中,递减可用资源。

    available_instance_count--;
    printk("Resource taken and available_instance_count = %d\n",  available_instance_count);
    C

    6.2 在模拟释放资源的函数 release_access() 中,递增可用资源。然后,在两个函数中都打印 available_instance_count。

    available_instance_count++;
    printk("Resource given and available_instance_count = %d\n", available_instance_count);
    C

    7. 构建应用程序并将其烧录到您的开发套件中。使用串口终端(如集成的 nRF Terminal 或 PuTTY),您应该会看到以下输出:

    Resource given and available_instance_count = 54
    Resource taken and available_instance_count = 53
    Resource given and available_instance_count = 54
    Resource taken and available_instance_count = 53
    Resource given and available_instance_count = 54
    Resource taken and available_instance_count = 53
    Resource given and available_instance_count = 54
    Resource taken and available_instance_count = 53
    Resource given and available_instance_count = 54
    Resource given and available_instance_count = 55
    Resource taken and available_instance_count = 54
    Resource given and available_instance_count = 55
    Terminal

    如您所见,打印的可用实例计数大于 10。对于我们仅有 10 个的物理资源来说,这不应该发生。

    但使用信号量可以轻松修复此问题,且应用程序无需承担原子性检查/验证可用资源内部计数的负担。

    9. 添加一个信号量,首先在定义消费者和生产者优先级之后,使用 K_SEM_DEFINE() 定义信号量,如下所示。

    K_SEM_DEFINE(instance_monitor_sem, 10, 10);
    C

    10.1 获取资源访问权限时获取信号量。

    将函数 get_access() 替换为以下代码片段。我们使用 k_sem_take() 来获取信号量。然后使用 k_sem_count_get() 获取当前的信号量计数。

    	k_sem_take(&instance_monitor_sem, K_FOREVER);
    	printk("Resource taken and available_instance_count = %d\n", k_sem_count_get(&instance_monitor_sem));
    C

    10.2 释放资源访问权限时给出信号量。

    将函数 release_access() 替换为以下代码片段。我们使用 k_sem_give() 来释放信号量。然后使用 k_sem_count_get() 获取当前的信号量计数。

    	k_sem_give(&instance_monitor_sem);
    	printk("Resource given and available_instance_count = %d\n", k_sem_count_get(&instance_monitor_sem));
    C

    11. 注释掉第 3 步中 available_instance_count 的定义。

    大功告成。您现在已经定义并使用了信号量。

    11. 构建应用程序并将其烧录到您的开发套件中。使用串口终端(如集成的 nRF Terminal 或 PuTTY),您应该会看到以下输出:

    *** Booting nRF Connect SDK ***
    Consumer thread started
    Resource taken and available_instance_count = 9
    Producer thread started
    Resource given and available_instance_count Resource taken and available_instance_count = 9
    = 10
    Resource given and available_instance_count = 10
    Resource taken and available_instance_count = 9
    Resource given and available_instanResource taken and available_instance_count = 9
    ce_count = 10
    Resource given and available_Resource taken and available_instance_count = 9
    instance_count = 10
    Resource given and available_instance_count = 10
    Resource taken and available_instance_count = 9
    Resource taken and available_instance_count = 8
    Resource given and available_instance_count = 9
    Resource taken and available_instance_count = 8
    Resource given and available_instance_count = 9Resource taken and available_instance_count = 8
    Resource taken and available_instance_count = 7
    
    Resource taken and available_instance_count = 6
    Resource given and available_instance_count = 7Resource taken and available_instance_count = 6
    
    Resource taken and available_instance_count = 5
    Resource taken and available_instance_count = 4
    Resource given and available_instance_count = 5
    Resource taken and available_instance_count = 4
    Resource given and available_instance_count = Resource taken and available_instance_count = 4
    5
    ResourcResource taken and available_instance_count = 4
    e given and available_instance_count = 5
    Resource taken and available_instance_count = 3
    Resource givResource taken and available_instance_count = 3
    en and available_instance_count = 4
    Resource taken and available_instance_count = 2
    Resource taken and available_instance_count = 1
    Resource given and available_instance_count = Resource taken and available_instance_count = 1
    2
    ResourcResource taken and available_instance_count = 1
    e given and available_instance_count = 2
    Resource taken and available_instance_count = 0
    Resource given and available_instance_count = 1
    Resource taken and available_instance_count = 0
    Resource given and available_instance_count = 1
    Resource taken and available_instance_count = 0
    Resource given and available_instance_count = 1
    Resource taken and available_instance_count = 0
    
    
    Terminal

    您可以看到消费者开始访问所有 10 个资源,而生产者线程同时创建资源,使生产保持平衡。

    此练习的解决方案可以在 GitHub 仓库中找到, l8/l8_e1_sol.

    Switch language?

    Progress is tracked separately for each language. Switching will continue from your progress in that language or start fresh if you haven't begun.

    Your current progress is saved, and you can switch back anytime.

    Register an account
    Already have an account? Log in
    (All fields are required unless specified optional)

    • 8 or more characters
    • Upper and lower case letters
    • At least one number or special character

    Forgot your password?
    Enter the email associated with your account, and we will send you a link to reset your password.