RT - Thread 커 널 소스 분석 - 신 호 량 실현 원리

목차
콘 셉 트
신 호 량 기본 조작
신 호 량 초기 화
획득 신호 량
방출 신호 량
총결산
콘 셉 트
신 호 량 기 개념 은 네덜란드 과학자 Dijkstr (가장 짧 은 경로 문 제 를 해결 한 친구 들) 가 도입 한 것 으로 서로 다른 프로 세 스 간 의 데이터 대상 을 조율 하 는 데 사용 된다. 신 호 량 은 본질 적 으로 하나의 계수기 로 특정한 자원 의 액세스 상황 을 기록 하여 여러 프로 세 스 가 공유 하 는 데이터 구조 에 제어 되 는 접근 을 제공한다.서로 다른 운영 체제 플랫폼 에서 모두 신 호 량 의 실현 이 있다. 각 플랫폼 은 실현 과 개념 에 있어 차이 가 있 지만 다음 과 같은 몇 가지 기능 과 떨 어 질 수 없다.
1. 신 호 량 초기 화
신 호 량 대상 만 들 기, 계수기 값 초기 화
2. 신호 수신 량
신 호 량 을 가 져 오 는 것 은 공유 자원 에 대한 접근 권한 을 가 져 오 는 것 과 같다.
3. 방출 신호 량
신 호 량 을 방출 하 는 것 은 공유 자원 에 대한 접근 권한 을 방출 하 는 것 과 같다.
다음은 RT - Thread 플랫폼 신 호 량 의 실현 으로 설명 하 겠 습 니 다.
 
신 호 량 기본 조작
신 호 량 초기 화
rt_err_t rt_sem_init(rt_sem_t    sem,
                     const char *name,
                     rt_uint32_t value,
                     rt_uint8_t  flag)
{
    RT_ASSERT(sem != RT_NULL);
    RT_ASSERT(value < 0x10000U);

    /* init object */
    rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);

    /* init ipc object */
    rt_ipc_object_init(&(sem->parent));

    /* set init value */
    sem->value = (rt_uint16_t)value;//   -       ,     1

    /* set parent */
    sem->parent.parent.flag = flag;

    return RT_EOK;
}

신 호 량 초기 화의 핵심 은 계수기 value 를 만 드 는 것 입 니 다. rtthread 는 시스템 자원 (신 호 량 도 시스템 자원) 을 편리 하 게 관리 하기 위해 대상 관리 방법 을 정 의 했 습 니 다. 모든 대상 은 rt 에서 계승 해 야 합 니 다.object, 관리 가 편리 합 니 다.
획득 신호 량
신 호 량 과 같은 희소 한 자원 은 언제든지 얻 을 수 있 는 것 이 아니 라 Liux 플랫폼 에서 시스템 자원 을 얻 는 작업 은 보통 최대 대기 시간 을 설정 합 니 다. 이 시간 이 초 과 된 후에 도 자원 을 얻 지 못 하면 돌아 갑 니 다. 마찬가지 로 RT - Thread 도 이런 고려 를 합 니 다. 신 호 량 인터페이스 에 대기 시간 이 포함 되 어 있 습 니 다. 다음 과 같 습 니 다.
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)
{
    register rt_base_t temp;
    struct rt_thread *thread;

    /* parameter check */
    RT_ASSERT(sem != RT_NULL);
    RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);

    RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(sem->parent.parent)));

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();//    

    RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s take sem:%s, which value is: %d
", rt_thread_self()->name, ((struct rt_object *)sem)->name, sem->value)); if (sem->value > 0)// 0, { /* semaphore is available */ sem->value --; /* enable interrupt */ rt_hw_interrupt_enable(temp);// } else {// <=0, /* no waiting, return with timeout */ if (time == 0) {// 0, rt_hw_interrupt_enable(temp); return -RT_ETIMEOUT; } else {// , >0, /* current context checking */ RT_DEBUG_IN_THREAD_CONTEXT; /* semaphore is unavailable, push to suspend list */ /* get current thread */ thread = rt_thread_self(); /* reset thread error number */ thread->error = RT_EOK; RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s
", thread->name)); /* suspend thread */ rt_ipc_list_suspend(&(sem->parent.suspend_thread), thread, sem->parent.parent.flag);// /* has waiting time, start thread timer */ if (time > 0) {// , RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list
", thread->name)); /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &time); rt_timer_start(&(thread->thread_timer)); } /* enable interrupt */ rt_hw_interrupt_enable(temp);// /* do schedule */ rt_schedule();// if (thread->error != RT_EOK) { return thread->error; } } } RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(sem->parent.parent))); return RT_EOK; }

신 호 량 카운터 도 다 중 스 레 드 공유 자원 으로 사용 전후 스위치 가 끊 겨 야 합 니 다.
세심 한 친 구 는 이 코드 가 우선 순위 반전 을 초래 할 수 있 는 문제 가 있다 는 것 을 알 게 될 것 이다.저 희 는 RT - Thread 커 널 소스 분석 - 우선 순위 반전 코드 실현 에서 분석 한 적 이 있 습 니 다. 시스템 자원 을 얻 기 때문에 연결 하면 우선 순위 반전 을 일 으 킬 수 있 습 니 다. 분명 합 니 다. rt_sem_take 는 우선 순위 반전 을 초래 할 수 있 습 니 다.사실은 이것 이 바로 신 호 량 의 장점 이다. 상호 배척 량 에 비해 신 호 량 은 소유자 의 개념 이 없고 간단 하고 작고 유연 하 며 효율 이 높 으 며 상호 배척 에 대한 요구 가 엄격 하지 않 은 시스템 에서 자주 사용 된다.
 
방출 신호 량
rt_err_t rt_sem_release(rt_sem_t sem)
{
    register rt_base_t temp;
    register rt_bool_t need_schedule;

    /* parameter check */
    RT_ASSERT(sem != RT_NULL);
    RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);

    RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(sem->parent.parent)));

    need_schedule = RT_FALSE;

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();//   

    RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s releases sem:%s, which value is: %d
", rt_thread_self()->name, ((struct rt_object *)sem)->name, sem->value)); if (!rt_list_isempty(&sem->parent.suspend_thread)) { /* resume the suspended thread */ rt_ipc_list_resume(&(sem->parent.suspend_thread)); need_schedule = RT_TRUE; } else sem->value ++; /* increase value */ /* enable interrupt */ rt_hw_interrupt_enable(temp); /* resume a thread, re-schedule */ if (need_schedule == RT_TRUE) rt_schedule(); return RT_EOK; }

신 호 량 을 방출 하 는 본질은 계수 기 를 + + 조작 하 는 것 이다. 신 호 량 을 방출 하면 스 레 드 스케줄 을 초래 할 수 있다. 현재 더 높 은 우선 순위 스 레 드 가 준비 되 지 않 더 라 도 신 호 량 을 방출 하면 신 호 량 에 걸 린 스 레 드 를 즉시 스케줄 링 할 수 있다.
여기 문제 가 있 습 니 다. rtsem_release 에서 이 신 호 량 에 걸 린 스 레 드 가 있 으 면 rt 를 실행 합 니 다.schedule 스케줄 링 (분명 한 것 은 현재 스 레 드 는 시스템 준비 스 레 드 대기 열 에 있 는 스 레 드 에 비해 현재 스 레 드 의 우선 순위 가 가장 높 습 니 다. 즉, 현재 시스템 의 준비 대기 열 에는 현재 스 레 드 보다 우선 순위 가 높 은 스 레 드 가 존재 하지 않 습 니 다) 그리고 rtsem_release 구현 중, 스케줄 링 이 필요 하 다 면 sem - > value + + 를 실행 하지 않 습 니 다. 이 는 문제 가 될 수 있 습 니 다. rt 를 실행 하면schedule, 지금 준비 되 어 있 는 대기 열 에 있 는 스 레 드 우선 순위 가 현재 스 레 드 보다 낮 으 면 스케줄 을 실행 하지 않 고 현재 스 레 드 가 계속 실행 되 지만 sem - > value + 를 실행 하지 않 는 것 을 발견 합 니 다. 이것 은 문 제 를 일 으 킬 수 있 는 것 이 아 닙 니까? 사실은 아무런 문제 가 발생 하지 않 습 니 다. 원인 은 rt 에 있 습 니 다.sem_take 의 실현, 다음은 rtsem_take 와 rtsem_release 의 프로 세 스 분석, 불필요 한 코드 제거:
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)
{
	...
    if (sem->value > 0)
    {
        
        sem->value --;
		...
    }
    else
    {//       ,     rt_sem_take  ,        sem->value--  ,      rt_sem_release    ,       re_sem_release     ,      sem->value++   
        if (time == 0)
        {
            ...
        }
        else
        {
            ...
            rt_schedule();
			...
        }
    }
	...
}

rt_err_t rt_sem_release(rt_sem_t sem)
{
	...
    if (!rt_list_isempty(&sem->parent.suspend_thread))
    {//            ,              (      ,        ,                   ),    sem->value++  
        /* resume the suspended thread */
        rt_ipc_list_resume(&(sem->parent.suspend_thread));
        need_schedule = RT_TRUE;
    }
    else
        sem->value ++;

    ...
    if (need_schedule == RT_TRUE)
        rt_schedule();

    return RT_EOK;
}

 
총결산
신 호 량 은 본질 적 으로 계수기 로 계수 기 는 임계 자원 에 위치 하고 계산 기 를 조작 할 때 도 스위치 를 끊 어야 한다.신 호 량 의 실현 이 간단 하고 상호 배척 량 에 비해 신 호 량 은 소유자 의 개념 이 없 으 며 간단 하고 작고 유연 하 며 효율 이 높 지만 우선 순위 반전 을 초래 할 수 있 고 상호 배척 에 대한 요구 가 엄격 하지 않 은 시스템 에서 자주 사용 된다.또한, 현재 더 높 은 우선 순위 스 레 드 가 스케줄 러 가 없 더 라 도 신 호 량 (mutex) 을 방출 하면 스케줄 러 가 스 레 드 스 케 쥴 러 를 실행 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기