2014-03-25 75 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

遞歸互斥的想法是,它可以被當前持有鎖的線程成功重新鎖定。例如:

,如果我有一些互斥這樣的(這是僞代碼):

mutex l; 
recursive_mutex r; 

在一個單獨的線程,如果我這樣做:

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

r.lock(); 
r.lock(); 
r.lock(); // this would all pass though with no issue. 

在實現遞歸互斥體時,您需要檢查threadId是否鎖定了它,如果鎖定了它,並且它與當前的threa匹配d 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(),當從bar()調用foo()時,線程會自我死鎖,因爲普通的互斥鎖()函數在互斥鎖解鎖之前不會返回,並且沒有其他線程可以解鎖它。

您的recursive_mutex_lock()需要區分這些情況; (1)互斥體未被鎖定,(2)互斥體已被鎖定,但調用線程是所有者,(3)互斥體已被其他線程鎖定。 (3)需要阻塞調用線程,直到擁有者完全解鎖互斥鎖爲止。此時,它轉換爲情況(1)。這裏有一個提示:用條件變量處理case(3)。也就是說,當調用線程不是所有者時,調用線程應該執行pthread_condition_wait(...)調用。