핸드 핸드 리 눅 스 구동 7 - 커 널 상호 배척 자물쇠

상호 배척 체 개술
신 호 량 은 병렬 처리 환경 에서 여러 개의 프로세서 가 특정한 공공 자원 에 접근 하 는 것 을 보호 하 는 메커니즘 으로 mutex 는 상호 배척 작업 에 사용 된다.신 호 량 의 count 를 1, down () / up () 으로 초기 화하 면 mutex 와 유사 한 역할 을 할 수 있 습 니 다.
mutex 의 의 미 는 신 호 량 에 비해 간단 하고 가 볍 습 니 다. 잠 금 경쟁 이 치열 한 테스트 장면 에서 mutex 는 신 호 량 보다 집행 속도 가 빠 르 고 확장 성 이 좋 습 니 다. 또한 mutex 데이터 구조의 정 의 는 신 호 량 보다 적 습 니 다.
mutex 의 장점
  • mutex 는 신 호 량 에 비해 효율 적 인 것 이 많다.
  • mutex 가 가장 먼저 자전 대기 체 제 를 실현
  • mutex 는 잠 자기 전에 자 물 쇠 를 가 져 오 려 고 시도 합 니 다
  • mutex 는 MCS 를 실현 하여 여러 개의 CPU 경쟁 용 잠 금 으로 인해 CPU 고속 캐 시 가 흔 들 리 는 현상 을 피한다.

  • mutex 사용 주의사항:
  • 같은 시각 에 하나의 스 레 드 만 mutex 를 가 질 수 있 습 니 다.
  • 자물쇠 소지 자만 잠 금 을 풀 수 있다.다른 프로 세 스에 서 mutex 를 가지 고 있 을 수 없습니다.
  • 재 귀적 으로 잠 금 을 추가 하고 잠 금 을 풀 수 없습니다.
  • 프로 세 스 가 mutex 를 가지 고 있 을 때 프로 세 스 를 종료 할 수 없습니다.
  • mutex 는 공식 API 를 사용 하여 초기 화 해 야 합 니 다.
  • mutex 는 잠 을 잘 수 있 기 때문에 처리 프로그램 을 중단 하거나 하반기 에 사용 할 수 없습니다. 예 를 들 어 tasklet, 타이머 등 입 니 다.

  • 디 렉 터 리:
    /linux/include/linux/mutex.h
    
    /*
     * Simple, straightforward mutexes with strict semantics:
     *
     * - only one task can hold the mutex at a time
     * - only the owner can unlock the mutex
     * - multiple unlocks are not permitted
     * - recursive locking is not permitted
     * - a mutex object must be initialized via the API
     * - a mutex object must not be initialized via memset or copying
     * - task may not exit with mutex held
     * - memory areas where held locks reside must not be freed
     * - held mutexes must not be reinitialized
     * - mutexes may not be used in hardware or software interrupt
     *   contexts such as tasklets and timers
     *
     * These semantics are fully enforced when DEBUG_MUTEXES is
     * enabled. Furthermore, besides enforcing the above rules, the mutex
     * debugging code also implements a number of additional features
     * that make lock debugging easier and faster:
     *
     * - uses symbolic names of mutexes, whenever they are printed in debug output
     * - point-of-acquire tracking, symbolic lookup of function names
     * - list of all locks held in the system, printout of them
     * - owner tracking
     * - detects self-recursing locks and prints out all relevant info
     * - detects multi-task circular deadlocks and prints out all affected
     *   locks and tasks (and only those tasks)
     */
    struct mutex {
         
      /* 1: unlocked, 0: locked, negative: locked, possible waiters */
      atomic_t    count;
      spinlock_t    wait_lock;
      struct list_head  wait_list;
    #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
      struct task_struct  *owner;
    #endif
    #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
      void      *spin_mlock;  /* Spinner MCS lock */
    #endif
    #ifdef CONFIG_DEBUG_MUTEXES
      const char     *name;
      void      *magic;
    #endif
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
      struct lockdep_map  dep_map;
    #endif
    };
    


    역할 및 접근 규칙:
  • 상호 배척 자 물 쇠 는 주로 내부 핵 중의 상호 배척 방문 기능 을 실현 하 는 데 쓰 인 다.커 널 상호 배척 자 물 쇠 는 원자 API 에서 이 루어 지지 만 커 널 사용자 에 게 는 보이 지 않 는 다.
  • 그 방문 에 대해 반드시 규칙 을 지 켜 야 한다. 같은 시간 에 하나의 임무 만 상호 배척 자 물 쇠 를 가지 고 있 을 수 있 고 이 임무 만 상호 배척 자 물 쇠 를 풀 수 있다.상호 배척 자 물 쇠 는 재 귀 잠 금 이나 잠 금 해 제 를 할 수 없습니다.상호 배척 대상 은 memset 이나 복사 로 초기 화 되 지 않 고 API 를 통 해 초기 화 되 어야 합 니 다.하나의 임 무 는 상호 배척 자 물 쇠 를 가지 고 있 을 때 끝 낼 수 없다.상호 배척 자물쇠 가 사용 하 는 메모리 영역 은 방출 될 수 없습니다.사용 중인 상호 배척 자 물 쇠 는 다시 초기 화 될 수 없습니다.또한 상호 배척 자 물 쇠 는 문맥 을 중단 하 는 데 사용 할 수 없습니다.
  • 상호 배척 잠 금 은 현재 커 널 신 호 량 옵션 보다 빠 르 고 더욱 치밀 하 다.

  • 상호 배척 체 의 사용
    초기 화
    정적 정 의 는 다음 과 같 습 니 다.
    DEFINE_MUTEX(name);
    

    mutex 를 동적 으로 초기 화 합 니 다. 다음 과 같 습 니 다.
    mutex_init(&mutex);
    

    구체 적 인 실현 은 다음 과 같다.
    #define mutex_init(mutex) \
    do {							\
    	static struct lock_class_key __key;		\
    							\
    	__mutex_init((mutex), #mutex, &__key);		\
    } while (0)
    
    void
    __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
    {
         
    	atomic_set(&lock->count, 1);
    	spin_lock_init(&lock->wait_lock);
    	INIT_LIST_HEAD(&lock->wait_list);
    	mutex_clear_owner(lock);
    #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
    	lock->spin_mlock = NULL;
    #endif
    
    	debug_mutex_init(lock, name, key);
    }
    

    상호 배척 자 물 쇠 를 신청 하 다.
    mutex 작업 목록 은 다음 과 같 습 니 다.
    방법.
    묘사 하 다.
    mutex_lock(struct mutex*)
    지정 한 mutex 에 자 물 쇠 를 잠 그 고 사용 하지 않 으 면 잠 을 잔다.
    mutex_unlock(struct mutex*)
    지정 한 mutex 잠 금 해제
    mutex_trylock(struct mutex*)
    보기 에서 지정 한 mutex 를 가 져 옵 니 다. 성공 하면 1 을 되 돌려 줍 니 다.그렇지 않 으 면 자물쇠 가 져 옵 니 다. 반환 값 은 0 입 니 다.
    mutex_is_lock(struct mutex*)
    자물쇠 가 징용 되면 1 을 되 돌려 줍 니 다.그렇지 않 으 면 0 으로 돌아 갑 니 다.
    mutex 의 간결 성과 효율 성 은 사용 신 호 량 보다 더 많은 제한 성에 서 비롯 된다.이것 은 신 호 량 과 다르다. 왜냐하면 mutex 는 Dijkstra 디자인 의 취지 에서 가장 기본 적 인 행 위 를 실 현 했 기 때문이다.따라서 mutex 의 사용 장면 은 상대 적 으로 엄격 하 다.
    (1) 코드: linux / kernel / mutex. c
    void inline fastcall __sched mutex_lock(struct mutex *lock);   
     //     。
    

    실제로 count 에 게 자감 작업 을 한 다음 에 자체 의 자전 자 물 쇠 를 사용 하여 임계 구역 에 들 어가 조작 합 니 다.먼저 count 의 값 을 얻 고 count 를 - 1 로 설정 하 며 원래 count 가 1 로 설정 되 어 있 으 면 서로 배척 하 는 자 물 쇠 를 얻 을 수 있다 고 판단 하면 직접 얻 고 뛰 어 내 립 니 다.그렇지 않 으 면 순환 에 들 어가 상호 배척 잠 금 상 태 를 반복 적 으로 테스트 한다.순환 에서 도 먼저 상호 배척 잠 금 의 원래 상 태 를 얻 고 이 를 - 1 로 판단 하 며 가 져 올 수 있다 (1 과 같다) 면 순환 을 종료 합 니 다. 그렇지 않 으 면 현재 프로 세 스 의 상 태 를 중단 할 수 없 는 상태 로 설정 하고 자신의 자 물 쇠 를 풀 고 수면 상태 에 들 어가 서 조절 이 깨 어 날 때 자신의 자 물 쇠 를 얻 고 새로운 조회 에 들 어가 자신의 상 태 를 조회 합 니 다.순환
    (2) 구체 적 으로 linux / kernel / mutex. c 참조
    int fastcall __sched mutex_lock_interruptible(struct mutex *lock)

    mutex lock () 과 마찬가지 로 상호 배척 자 물 쇠 를 가 져 옵 니 다. 상호 배척 자 물 쇠 를 얻 거나 잠 에 들 어 갈 때 까지 0 으로 돌아 갑 니 다. 자 물 쇠 를 가 져 오 기 를 기다 리 는 동안 수면 상태 에 들 어가 신 호 를 받 으 면 EINIR 로 돌아 갑 니 다.
    (3) 리 눅 스 / kernel / mutex. c 참조
    int fastcall __sched mutex_trylock(struct mutex *lock);
    

    상호 배척 자 물 쇠 를 가 져 오 려 고 합 니 다. 성공 적 으로 가 져 오 면 1 로 돌아 갑 니 다. 그렇지 않 으 면 0 으로 돌아 가 고 기다 리 지 않 습 니 다.
    상호 배척 자 물 쇠 를 방출 하 다.
    구체 적 으로 linux / kernel / mutex. c 참조
    void fastcall mutex_unlock(struct mutex *lock);
    

    현재 프로 세 스에 서 가 져 온 상호 배척 자 물 쇠 를 풀 수 있 습 니 다. 이 함 수 는 중단 컨 텍스트 에 사용 할 수 없 으 며 잠 겨 있 지 않 은 상호 배척 자 물 쇠 를 풀 수 없습니다.
    상호 배척 자물쇠 시용 주의사항
  • 언제든지 하나의 임무 만 mutex 를 소지 할 수 있다. 즉, mutex 의 사용 계 수 는 영원히 1
  • 이다.
  • mutex 자 물 쇠 를 잠 그 는 사람 에 게 재 잠 금 해 제 를 책임 져 야 합 니 다. 한 컨 텍스트 에 mutex 를 잠 그 지 못 하고 다른 컨 텍스트 에서 잠 금 을 풀 어 줍 니 다. 이 제한 으로 인해 mutex 는 커 널 과 사용자 공간 이 복잡 한 동기 화 장면 에 적합 하지 않 습 니 다. 가장 자주 사용 하 는 방식 은 같은 컨 텍스트 에 잠 금 을 잠 그 고 잠 금 을 푸 는 것 입 니 다.
  • 재 귀적 으로 잠 금 을 잠 그 고 잠 금 을 풀 수 없습니다. 즉, 같은 자 물 쇠 를 재 귀적 으로 가지 고 있 을 수 없습니다. 마찬가지 로 풀 린 mutex
  • 를 다시 잠 글 수 없습니다.
  • mutex 를 가지 고 있 을 때 프로 세 스 를 종료 할 수 없습니다
  • mutex 는 중단 되 거나 하반기 에 사용 할 수 없 으 며, mutex trylock () 을 사용 하 더 라 도 사용 할 수 없습니다
  • mutex 는 공식 API 관 리 를 통 해서 만 관리 할 수 있 습 니 다. 위 절 에서 설명 한 방법 으로 만 초기 화 할 수 있 습 니 다. 복사 되 거나 수 동 으로 초기 화 되 거나 중복 초기 화 되 어 서 는 안 됩 니 다
  • 신 호 량 과 상호 배척 체
    상호 배척 체 와 신 호 량 이 비슷 하 다. 커 널 에 있 는 두 가지 공존 은 헷 갈 릴 수 있다. 다행히 이들 의 표준 사용 방식 은 모두 간단 한 규범 이 있다. mutex 의 특정한 제약 이 사용 을 방해 하지 않 는 한 신 호 량 보다 mutex 를 우선 사용 해 야 한다. 새로운 코드 를 쓸 때 만 특수 한 상황 (보통 바 텀 코드) 에 부 딪 힐 수 있다.신 호 량 을 사용 해 야 합 니 다. 따라서 mutex 를 선택 하 는 것 을 권장 합 니 다. 제약 조건 을 만족 시 키 지 못 하고 다른 선택 이 없 을 경우 신 호 량 을 선택 하 는 것 을 고려 하 십시오.
    자 회전 자물쇠 와 상호 배척 체 사용 장소
    자 물 쇠 를 언제 사용 하 는 지, 상호 배척 체 (또는 신 호 량) 를 언제 사용 하 는 지 알 아 보 는 것 은 좋 은 코드 를 만 드 는 데 중요 하지만, 대부분의 경우 에는 많은 고려 가 필요 하지 않 습 니 다. 인 터 럽 트 컨 텍스트 에 서 는 자 물 쇠 를 사용 할 수 있 을 뿐, 작업 이 잠 들 때 는 상호 배척 체 만 사용 할 수 있 기 때 문 입 니 다.
    다음은 각종 자물쇠 의 수요 상황 을 정리 하 겠 습 니 다.
    수요
    제안 한 잠 금 방법
    저비용 에 자 물 쇠 를 채우다.
    자동 잠 금 우선 사용
    단기 잠 금
    자동 잠 금 우선 사용
    장기 잠 금
    우선 상호 배척 체 사용
    인 터 럽 트 상하 문 에 잠 금 추가
    자 물 쇠 를 사용 하 다
    자 물 쇠 를 가지 고 있 으 면 잠 이 필요 하 다.
    상호 배척 체 를 사용 하 다
    상호 배척 잠 금 및 잠 금 해제 사용 사례
    사용 방법 은 다음 과 같다.
    1. struct mutex mutex;
    2. mutex_init(&mutex); /*  */
    3. //  
    4. mutex_lock(&mutex);
    5.  
    6. //   
    7. 
    8. //  
    9. mutex_unlock(&mutex);
    

    상호 배척 체 는 더 이상 사용 계 수 를 관리 할 필요 가 없 기 때문에 간략화 판 신 호 량 임 을 알 수 있다.
    아래 네트워크 카드 DM 9000 의 구동 입 니 다. 그 중에서 eeprom 에 기 록 된 동작 은 mutex 체 제 를 사 용 했 습 니 다.
    static void
    dm9000_write_eeprom(board_info_t *db, int offset, u8 *data)
    {
         
    	unsigned long flags;
    
    	if (db->flags & DM9000_PLATF_NO_EEPROM)
    		return;
    
    	mutex_lock(&db->addr_lock);
    
    	spin_lock_irqsave(&db->lock, flags);
    	iow(db, DM9000_EPAR, offset);
    	iow(db, DM9000_EPDRH, data[1]);
    	iow(db, DM9000_EPDRL, data[0]);
    	iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);
    	spin_unlock_irqrestore(&db->lock, flags);
    
    	dm9000_wait_eeprom(db);
    
    	mdelay(1);	/* wait at least 150uS to clear */
    
    	spin_lock_irqsave(&db->lock, flags);
    	iow(db, DM9000_EPCR, 0);
    	spin_unlock_irqrestore(&db->lock, flags);
    
    	mutex_unlock(&db->addr_lock);
    }
    

    eeprom 에 데 이 터 를 기록 할 때마다 (임계 자원 에 접근) 이 자원 에 대응 하 는 상호 배척 잠 금 db - > addr lock 을 먼저 얻 고 사용 이 완료 되면 이 잠 금 을 풀 어야 합 니 다.
    리 눅 스에 관 한 더 많은 자 료 를 얻 으 려 면 공식 번호 인 '리 눅 스 한 입' 에 관심 을 가 져 주 십시오.

    좋은 웹페이지 즐겨찾기