2012-02-13 43 views
6

Sử dụng trylock:Làm thế nào để sử dụng pthread_mutex_trylock?

FILE   *fp; 
pthread_mutex_t demoMutex; 

void * printHello (void* threadId) 
{ 
    pthread_mutex_trylock (&demoMutex); 

    pthread_t  writeToFile = pthread_self(); 
    unsigned short iterate; 
    for (iterate = 0; iterate < 10000; iterate++) 
    { 
     fprintf (fp, " %d ", iterate,   4); 
     fprintf (fp, " %lu ", writeToFile, sizeof (pthread_t)); 
     fprintf (fp, "\n",  writeToFile, 1); 
    } 

    pthread_mutex_unlock (&demoMutex); 
    pthread_exit (NULL); 
} 

và sau đó main():

int main() 
{ 
    pthread_t  arrayOfThreadId [5]; 
    int     returnValue; 
    unsigned int iterate; 

    fp = fopen ("xyz", "w"); 
    pthread_mutex_init (&demoMutex, NULL); 

    for (iterate = 0; iterate < 5; iterate++) 
    { 
     if (returnValue = pthread_create (&arrayOfThreadId [iterate], 
            NULL, 
            printHello, 
            (void*) &arrayOfThreadId [iterate]) != 0) 
     { 
      printf ("\nerror: pthread_create failed with error number %d", returnValue); 
     } 
    } 

    for (iterate = 0; iterate < 5; iterate++) 
     pthread_join (arrayOfThreadId [iterate], NULL); 

    return 0; 
} 

Ở đây, đầu ra đầu tiên in một số trong những chủ đề đầu tiên và sau đó là phần còn lại, và sau đó một lần nữa là người đầu tiên. Khóa không hoạt động. Nếu tôi thay thế tương tự với pthread_mutex_lock mọi thứ sẽ được hiển thị rất tuần tự!

Lỗi vô lý ở đây là gì?

Trả lời

21

Không có ý nghĩa khi gọi pthread_mutex_trylock() mà không kiểm tra kết quả.

Nếu không mua được mutex, bạn nên không nhập phần quan trọng và bạn nên không mở khóa sau. Ví dụ, bạn có thể viết lại nó như vậy (lưu ý rằng bạn cũng đang rất bối rối về cách fprintf() nên được gọi):

void *printHello(void *threadId) 
{ 
    if (pthread_mutex_trylock(&demoMutex) == 0) 
    { 
     unsigned short iterate; 
     for (iterate = 0; iterate < 10000; iterate++) 
     { 
      fprintf (fp, " %d\n", iterate); 
     } 

     pthread_mutex_unlock (&demoMutex); 
    } 

    pthread_exit (NULL); 
} 

Tuy nhiên, nó có thể làm cho tinh thần hơn để sử dụng pthread_mutex_lock() thay vì pthread_mutex_trylock(), vì vậy mà chủ đề của bạn sẽ đợi cho mutex khả dụng nếu nó được sử dụng. pthread_mutex_lock() là trong hầu như tất cả các trường hợp những gì bạn muốn; Biến thể _trylock chỉ để tối ưu hóa một số trường hợp bất thường - nếu bạn từng gặp phải tình huống khi cần _trylock, bạn sẽ biết.

+0

Vì tò mò, bạn có thể cung cấp ví dụ trong đó '..._ lock()' được ưa thích hơn '..._ trylock()'? Ví dụ nếu bạn muốn thực hiện một thời gian chờ, sẽ không 'trylock' là sự lựa chọn? Hay nó không có ý nghĩa để làm một thời gian chờ? – theMayer

+1

'..._ lock()' là tùy chọn thích hợp trong hầu hết các trường hợp vì trong hầu hết các trường hợp, luồng không thể thực hiện bất kỳ tiến trình nào hữu ích về phía trước mà không dùng mutex. Trong trường hợp này, nếu một '... trylock()' được sử dụng và không thể lấy khóa, lựa chọn duy nhất là lặp lại và cố gắng khóa nó lại. Thời gian chờ chỉ nên được yêu cầu trong trường hợp cần có sự kiện bên ngoài cho tiến trình tiến, có xu hướng ánh xạ tới biến điều kiện và do đó có thể sử dụng 'pthread_cond_timedwait()'. Một sự chờ đợi không bị chặn trên một mutex chỉ ra một vấn đề trong chính mã đó chứ không phải là một điều kiện đặc biệt. – caf

+0

Đồng ý với câu cuối cùng ở đó ... Tôi có một số mã di sản mà nhà phát triển có chút tham vọng và có thể không hiểu cách hoạt động của luồng. Mã này cũng đang cố gắng ngủ luồng chỉ trong một mili giây một lần. Bạn phải cười, nếu không nó sẽ làm bạn khóc! – theMayer

0

Mã này có nghĩa là chặn để đảm bảo loại trừ lẫn nhau nơi bạn gọi pthread_mutex_trylock(). Nếu không nó là hành vi không xác định. Vì vậy, bạn phải gọi pthread_mutex_lock().

0

phiên bản sửa đổi của lực bị khóa với vòng lặp while nên ổn định hơn.

void *printHello(void *threadId) 

{ 

    while (pthread_mutex_trylock(&demoMutex) == 0) 

    { 

     unsigned short iterate; 

     for (iterate = 0; iterate < 10000; iterate++) 

     { 

      fprintf (fp, " %d\n", iterate); 

     } 


     pthread_mutex_unlock (&demoMutex); 

     break; 

    } 

pthread_exit (NULL); 

} `

4
... 
while (pthread_mutex_trylock(&demoMutex) == 0) 
... 

Mã của bạn làm cho không có ý nghĩa. Nó bị khóa ở đâu? Nó giống như một spinlock không hoạt động sử dụng nhiều CPU hơn ?!

trylock trả về 0 khi nó khóa, vì vậy:

if(!pthread_mutex_trylock(&demoMutex)) 
{ 
    // mutex locked 
} 

Các pthread_mutex_trylock() chức năng phải trả lại không nếu một khóa trên đối tượng mutex tham chiếu bởi mutex được mua lại. Nếu không, một lỗi số sẽ được trả lại để cho biết lỗi.

0

Việc sử dụng pthread_mutex_trylock được sử dụng để đảm bảo rằng bạn sẽ không gây ra cuộc đua cho một lệnh cụ thể. Để làm như vậy, bạn phải sử dụng pthread_mutex_trylock làm điều kiện! không cho rằng nó sẽ tự hoạt động. example- trong khi (pthread_mutex_trylock (& my_mutex) == 0) { printf ("Biến tần nằm trong tầm kiểm soát của tôi !!\ N ");. }

cách mà bạn có thể chắc chắn rằng ngay cả khi mutex hiện đang bị khóa, bạn đang làm abusy-chờ đợi cho nó ở chỗ chủ đề cụ thể

3

caf đã có một câu trả lời tuyệt vời về cách Tôi chỉ phải lấy lời giải thích đó cho bản thân mình, tuy nhiên tôi đã biết rằng pthread_mutex_lock() có nhiều chi phí hơn trong lớp và chỉ kiểm tra nó bằng cách sử dụng lib <time.h> và hiệu năng cho vòng lặp của tôi đã tăng lên đáng kể. xu kể từ khi ông đề cập rằng có thể bạn nên sử dụng pthread_mutex_lock() thay thế!

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 

#define NUM_THREADS 4 
#define LOOPS 100000 

int counter; 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 

// using pthread_mutex_lock 
void* worker() { 
    for (int i = 0; i < LOOPS; i++) { 
     pthread_mutex_lock(&mutex); 
     counter++; 
     pthread_mutex_unlock(&mutex); 
    } 
    pthread_exit(NULL); 
} 

// using try_lock - obviously only use one at a time 
void* worker() { 
    for (int i = 0; i < LOOPS; i++) { 
     while (pthread_mutex_trylock(&mutex) != 0) { 
      // wait - treated as spin lock in this example 
     } 

     counter++; 
     pthread_mutex_unlock(&mutex); 
    } 
    pthread_exit(NULL); 
} 

int main(int argc, char *argv[]) { 
    clock_t begin = clock(); 
    pthread_t t[NUM_THREADS]; 
    int rc; 

    counter = 0; 

    for (int i = 0; i < NUM_THREADS; i++) { 
     rc = pthread_create(&t[i], NULL, worker, NULL); 

     if (rc) { 
      printf("Thread #%d failed\n", i); 
     } 
    } 

    for (int i = 0; i < NUM_THREADS; i++) { 
     pthread_join(t[i], NULL); 
    } 

    printf("%d\n", counter); 
    clock_t end = clock(); 
    double time = (double)(end - begin)/CLOCKS_PER_SEC; 

    printf("Time Spent: %f", time); 

    return 0; 
} 

Rõ ràng bạn sẽ bình luận ra một công nhân để kiểm tra nó, nhưng nếu bạn thử nó, tôi nhận được Time Spent: 1.36200 là trung bình cho pthread_mutex_lock()Time Spent: 0.36714 cho pthread_mutex_trylock().

Chuyển nhanh hơn nếu bạn sử dụng Atomics.

+0

Câu trả lời này xứng đáng được bỏ phiếu. Đối với một số tình huống nhất định, bạn cần sử dụng _trylock, nhưng hãy đảm bảo bạn kiểm tra kết quả kết quả của kết quả. –

+0

Tôi tự hỏi liệu khóa quay trong trường hợp này có thể là nguyên nhân làm tăng hiệu suất của bạn không? Xem https://stackoverflow.com/questions/6603404/when-is-pthread-spin-lock-the-right-thing-to-use-over-e-g-a-pthread-mutex – theMayer

Các vấn đề liên quan