2014-03-25 1 views
4

저는 학교 실험실에서 일하고 있습니다. 카운팅 프로그램을위한 재귀 뮤텍스 잠금을 만들도록 지시 받았습니다. 나는 어떤 코드를 작성했는데 (작동하지 않는다), 재귀 적 뮤텍스 잠금을 사용하는 실제적인 생각을 이해할 수 없기 때문에 이것이 대부분이라고 생각한다. 반복적 인 뮤텍스 잠금이 수행해야하는 작업을 정교하게 해석 할 수 있습니까?재귀 뮤텍스 락의 아이디어

일반 정보 : 답변을 요청하는 것이 아니며, 재귀 적 뮤텍스 잠금이 수행해야하는 작업에 대한 설명이 필요합니다.

또한 누군가 궁금하다면 여기에 필요한 코드가 있습니다. 편집/구현중인 코드는 recmutex.c입니다.

recmutex.h

#include <pthread.h> 

/* 
* The recursive_mutex structure. 
*/ 

struct recursive_mutex { 

    pthread_cond_t cond; 
    pthread_mutex_t mutex; //a non-recursive pthread mutex 
    pthread_t   owner; 
    unsigned int  count; 
    unsigned int  wait_count; 
}; 

typedef struct recursive_mutex recursive_mutex_t; 


/* Initialize the recursive mutex object. 
*Return a non-zero integer if errors occur. 
*/ 

int recursive_mutex_init (recursive_mutex_t *mu); 


/* Destroy the recursive mutex object. 
*Return a non-zero integer if errors occur. 
*/ 

int recursive_mutex_destroy (recursive_mutex_t *mu); 


/* The recursive mutex object referenced by mu shall be 
    locked by calling pthread_mutex_lock(). When a thread 
    successfully acquires a mutex for the first time, 
    the lock count shall be set to one and successfully return. 
    Every time a thread relocks this mutex, the lock count 
    shall be incremented by one and return success immediately. 
    And any other calling thread can only wait on the conditional 
    variable until being waked up. Return a non-zero integer if errors occur. 
*/ 
int recursive_mutex_lock (recursive_mutex_t *mu); 


/* The recursive_mutex_unlock() function shall release the 
    recursive mutex object referenced by mu. Each time the owner 
    thread unlocks the mutex, the lock count shall be decremented by one. 
    When the lock count reaches zero, the mutex shall become available 
    for other threads to acquire. If a thread attempts to unlock a 
    mutex that it has not locked or a mutex which is unlocked, 
    an error shall be returned. Return a non-zero integer if errors occur. 
*/ 

int recursive_mutex_unlock (recursive_mutex_t *mu); 

recmutex.c는 : 상기 언급 된 계산 프로그램 : 재귀 뮤텍스

#include <stdio.h> 
#include <pthread.h> 
#include <errno.h> 
#include "recmutex.h" 

int recursive_mutex_init (recursive_mutex_t *mu){ 
    int err; 
    err = pthread_mutex_init(&mu->mutex, NULL); 
    if(err != 0){ 
     perror("pthread_mutex_init"); 
     return -1; 
    }else{ 
     return 0; 
    } 
    return 0; 
} 

int recursive_mutex_destroy (recursive_mutex_t *mu){ 
    int err; 
    err = pthread_mutex_destroy(&mu->mutex); 
    if(err != 0){ 
     perror("pthread_mutex_destroy"); 
     return -1; 
    }else{ 
     return 1; 
    } 
    return 0; 
} 

int recursive_mutex_lock (recursive_mutex_t *mu){ 

    if(mutex_lock_count == 0){ 
     pthread_mutex_lock(&mu->mutex); 
     mu->count++; 
     mu->owner = pthread_self(); 
     printf("%s", mu->owner); 
     return 0; 
    }else if(mutex_lock_count > 0){ 
     pthread_mutex_lock(&mu->mutex); 
     mu->count++; 
     mu->owner = pthread_self(); 
     return 0; 
    }else{ 
     perror("Counter decremented incorrectly"); 
     return -1; 
    } 
} 

int recursive_mutex_unlock (recursive_mutex_t *mu){ 

    if(mutex_lock_count <= 0){ 
     printf("Nothing to unlock"); 
     return -1; 
    }else{ 
     mutex_lock_count--; 
     pthread_mutex_unlock(&mu->mutex); 
     return 0; 
    } 
} 

count_recursive.cc위한 기능을 포함한다. recmutex 함수를 사용합니다.

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <ctype.h> 
#include <unistd.h> 
#include <assert.h> 
#include <string.h> 
#include "recmutex.h" 

//argument structure for the thread 
typedef struct _arg_{ 
    int n1; 
    int n2; 
    int ntimes; 
}Arg; 

int count; //global counter 
recursive_mutex_t mutex; //the recursive mutex 

void do_inc(int n){ 
    int ret; 
    if(n == 0){ 
    return; 
    }else{ 
    int c; 
    ret = recursive_mutex_lock(&mutex); 
    assert(ret == 0); 
    c = count; 
    c = c + 1; 
    count = c; 
    do_inc(n - 1); 
    ret = recursive_mutex_unlock(&mutex); 
    assert(ret == 0); 
    } 
} 

/* Counter increment function. It will increase the counter by n1 * n2 * ntimes. */ 
void inc(void *arg){ 
    Arg * a = (Arg *)arg; 
    for(int i = 0; i < a->n1; i++){ 
    for(int j = 0; j < a->n2; j++){ 
     do_inc(a->ntimes); 
    } 
    } 
} 

int isPositiveInteger (const char * s) 
{ 
    if (s == NULL || *s == '\0' || isspace(*s)) 
      return 0; 
    char * p; 
    int ret = strtol (s, &p, 10); 
    if(*p == '\0' && ret > 0) 
    return 1; 
    else 
    return 0; 
} 

int test1(char **argv){ 

    printf("==========================Test 1===========================\n"); 
    int ret; 
    //Get the arguments from the command line. 
    int num_threads = atoi(argv[1]); //The number of threads to be created. 
    int n1 = atoi(argv[2]);   //The outer loop count of the inc function. 
    int n2 = atoi(argv[3]);   //The inner loop count of the inc function. 
    int ntimes = atoi(argv[4]);  //The number of increments to be performed in the do_inc function. 

    pthread_t *th_pool = new pthread_t[num_threads]; 
    pthread_attr_t attr; 
    pthread_attr_init(&attr); 
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 

    ret = recursive_mutex_init(&mutex); 
    assert(ret == 0); 

    printf("Start Test. Final count should be %d\n", num_threads * n1 * n2 * ntimes); 

    // Create threads 
    for(int i = 0; i < num_threads; i++){ 
    Arg *arg = (Arg *)malloc(sizeof(Arg)); 
    arg->n1 = n1; 
    arg->n2 = n2; 
    arg->ntimes = ntimes; 
    ret = pthread_create(&(th_pool[i]), &attr, (void * (*)(void *)) inc, (void *)arg); 
    assert(ret == 0); 
    } 

    // Wait until threads are done 
    for(int i = 0; i < num_threads; i++){ 
    ret = pthread_join(th_pool[i], NULL); 
    assert(ret == 0); 
    } 

    if (count != num_threads * n1 * n2 * ntimes) { 
    printf("\n****** Error. Final count is %d\n", count); 
    printf("****** It should be %d\n", num_threads * n1 * n2 * ntimes); 
    } 
    else { 
    printf("\n>>>>>> O.K. Final count is %d\n", count); 
    } 

    ret = recursive_mutex_destroy(&mutex); 
    assert(ret == 0); 

    delete [] th_pool; 
    return 0; 
} 


int foo(){ 
    int ret; 
    printf("Function foo\n"); 
    ret = recursive_mutex_unlock(&mutex); 
    assert(ret != 0); 
    return ret; 
} 

//test a thread call unlock without actually holding it. 
int test2(){ 
    int ret; 
    printf("\n==========================Test 2==========================\n"); 
    pthread_t th; 
    pthread_attr_t attr; 
    pthread_attr_init(&attr); 
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 

    ret = recursive_mutex_init(&mutex); 
    ret = pthread_create(&th, &attr, (void * (*)(void *))foo, NULL); 

    printf("Waiting for thread to finish\n"); 
    ret = pthread_join(th, NULL); 
    assert(ret == 0); 
    return 0; 
} 


int main(int argc, char ** argv) 
{ 
    int ret; 
    count = 0; 

    if(argc != 5) { 
    printf("You must enter 4 arguments. \nUsage: ./count_recursive num_threads n1 n2 ntimes\n"); 
    return -1; 
    } 

    if(isPositiveInteger(argv[1]) != 1 || isPositiveInteger(argv[2]) != 1 || isPositiveInteger(argv[3]) != 1 || isPositiveInteger(argv[4]) != 1){ 
    printf("All the 4 arguments must be positive integers\n"); 
    return -1; 
    } 

    test1(argv); 

    test2(); 

    return 0; 
} 

답변

10

재귀 뮤텍스의 개념은 현재 잠금을 유지하고있는 스레드에 의해 성공적으로 다시 잠길 수 있다는 것입니다. 예를 들어 :

l.lock(); 
l.lock(); // this would hang the thread. 

하지만

r.lock(); 
r.lock(); 
r.lock(); // this would all pass though with no issue. 
: 나는 이런 짓을하는 경우 단일 스레드에서

mutex l; 
recursive_mutex r; 

:

나는 (이 의사이다)이 같은 일부 뮤텍스가 있다면

재귀 뮤텍스를 구현할 때 어떤 threadId가 잠겨 있는지, 잠겨져 있는지, 그리고 현재 쓰레드와 일치하는지 확인해야합니다 ID는 성공을 반환합니다.

+1

예. 그리고'pthread_self()'를 사용하여 스레드 ID를 얻을 수 있습니다 –

+0

^^ – DevNull

3

재귀 뮤텍스의 요점은, 당신이 쓸 수 있도록하는 것입니다 :

recursive_mutext_t rmutex; 

void foo(...) { 
    recursive_lock_lock(&rmutex); 
    ... 
    recursive_lock_unlock(&rmutex); 
} 

void bar(...) { 
    recursive_lock_lock(&rmutex); 
    ... 
    foo(...); 
    ... 
    recursive_lock_unlock(&rmutex); 
} 

void baz(...) { 
    ... 
    foo(...); 
    ... 
} 

함수 foo는() (잠겨있는 뮤텍스가 필요합니다,하지만 당신은 줄에서 하나를 호출 할 수 있도록하려면) 같은 뮤텍스가 이미 잠겨 있거나, baz() 뮤텍스가 잠겨 있지 않은 곳에서. 일반 뮤텍스()를 사용했다면 mutex 잠금이 풀릴 때까지 일반적인 뮤텍스 lock() 함수가 반환되지 않기 때문에 bar()에서 foo()를 호출하면 스레드가 자체 교착 상태가됩니다. 그것.

recursive_mutex_lock()은 이러한 경우를 구별해야합니다. (1) 뮤텍스가 잠겨 있지 않은 경우, (2) 뮤텍스가 이미 잠겨 있지만 호출 스레드가 소유자 인 경우, (3) 뮤텍스가 다른 스레드에 의해 이미 잠겨있는 경우.

사례 (3)은 소유자가 뮤텍스를 완전히 잠금 해제 할 때까지 호출 스레드를 차단해야합니다. 그 시점에서 사례 (1)로 변환됩니다. 힌트가 있습니다 : 조건 변수를 사용하여 case (3)를 처리하십시오. 즉, 호출 스레드가 소유자가 아닌 경우 호출 스레드는 pthread_condition_wait (...) 호출을 수행해야합니다.