zoukankan      html  css  js  c++  java
  • RT-Thread多线程导致的临界区问题

    临界资源是指一次仅允许一个线程使用的共享资源。不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它们进行访问。每个线程中访问临界资源的那段代码称为临
    界区( Critical Section),每次只准许一个线程进入临界区,进入后不允许其他线程进入。多线程程序的开发方式不同于裸机程序,多个线程在宏观上是并发运行的,因此使用一个共享资源是需要注意,否则就可能出现错误的运行结果。

    #include <rtthread.h>
    #include <stm32f10x.h>
    #include "test.h"
    
    rt_uint32_t  g_tmp;/* 定义一个全局变量*/
    
    /*  变量分配4字节对齐 */
    ALIGN(RT_ALIGN_SIZE)
    
    /*  静态线程的 线程堆栈*/
    static rt_uint8_t thread1_stack[512];
    static rt_uint8_t thread2_stack[512];
    
    /* 静态线程的 线程控制块 */
    static struct rt_thread thread_test1;
    static struct rt_thread thread_test2;
    
    
    static void test1_thread_entry(void* parameter);
    static void test2_thread_entry(void* parameter);
    
    void demo_thread_creat(void)
    {
        rt_err_t result;
    
        /* 创建静态线程 : 优先级 15 ,时间片 2个系统滴答 */
        result = rt_thread_init(&thread_test1,
                                "test1",
                                test1_thread_entry, RT_NULL,
                                (rt_uint8_t*)&thread1_stack[0], sizeof(thread1_stack), 16, 2);
    
        if (result == RT_EOK)
        {
            rt_thread_startup(&thread_test1);
        }
    
        /* 创建静态线程 : 优先级 16 ,时间片 1个系统滴答 */
        result = rt_thread_init(&thread_test2,
                                "test2",
                                test2_thread_entry, RT_NULL,
                                (rt_uint8_t*)&thread2_stack[0], sizeof(thread2_stack), 15, 1);
    
        if (result == RT_EOK)
        {
            rt_thread_startup(&thread_test2);
        }
    
    }
    
    void test1_thread_entry(void* parameter)
    {
        rt_uint32_t i;
    
        g_tmp = 0;
        rt_kprintf("g_tmp=:%d 
    ", g_tmp);
        for(i=0; i<10000; i++)
        {
            g_tmp++;
        }
        rt_kprintf("g_tmp=:%d 
    ", g_tmp);
    }
    
    void test2_thread_entry(void* parameter)
    {
        rt_thread_delay(100);// 1 rt_thread_delay(100);两种情况下得到两张图片

    g_tmp++;
    }

    结果分析:
    在 test1 线程的 for 循环中我们对 i 做了 10000 次累加,如果没有其他线程的“干预”,那么全局变量 g_tmp 的值应该是 10000,现在的输出结果是 10001,这意味全局变量 g_tmp 的值被线程 2 修改过。整个程序运行过程中各个线程的状态变化是这样的: rt_application_init 中创建两个线程之后,由于 test2 线程的优先级比 test1 线程的优先级高,因此 test2 线程先运行,其线程处理函数第一句为 rt_thread_delay(1), 这会使得 test2 线程被挂起,挂起时间为 1 个时间片,在 test2 线程挂起的这段时间中, test1 线程是所有就绪态线程中优先级最高的线程,因此被内核调度运行。 在 test1 线程执行了一部分代码后, 1 个 tick 时间到, test2 线程被唤醒,从而成为所有就绪线程中优先级最高的线程,因此会被立刻调度运行, test1 线程被 test2 线程抢占, test2 线程中对全局变量 g_tmp 做累加操作,接下来 test2 线程执行完毕, test1 线程再次被调度运行,根据程序的运行结果可以看出,此时 test1 线程继续执行,但是我们并不知道此时 test1 线程大致是从什么地方在开始执行的,从最后的输出结果来看,只能得知此时test1 线程还没有执行到第二条 rt_kprintf 输出语句。最后 test1 线程再次打印全局变量 g_tmp的值,其值就应该是 10001。当 test2线程中的第一句为 rt_thread_delay(100)的时候,在 test2线程休眠的整个时间里,test1 线程都已经执行完毕,因此最后的输出结果为 10000。
    从以上可以看到: 当公共资源在多个线程中公用时,如果缺乏必要的保护错误,最后的输出结果可能与预期的结果完全不同。为了解决这种问题,需要引入线程间通信机制,这就
    是所谓的 IPC 机制( Inter-Process Communication)。

  • 相关阅读:
    图片验证码制作
    上传图片加水印
    组合查询加分页
    C# 数据类型 数据转换 自己的见解和方式
    C# 基础控制台程序的创建,输出,输入,定义变量,变量赋值,值覆盖,值拼接,值打印
    关于Spring注解
    java I/O
    关于web.xml配置
    第7章 使用springMVC构建Web应用程序 7.1 springMVC配置
    js配合c3制作一个动态钟表
  • 原文地址:https://www.cnblogs.com/yygsj/p/5501016.html
Copyright © 2011-2022 走看看