2009-11-22 31 views
17

Nếu bạn mở khóa một mutex đã được mở khóa, hành vi không an toàn, an toàn hoặc không xác định?Nếu bạn mở khóa một mutex đã được mở khóa, hành vi không xác định?

Mục đích của câu hỏi liên quan đến mã sau đây, nơi tôi không biết liệu có nên mở khóa các mutex trong khối if hay ngay bên ngoài khối if.

// This chunk of code makes dual locking semi-autonomous. 
    int c_lckd = 0, q_lckd = 0; 
    if (pthread_mutex_trylock(&crunch_mutex) == 0) c_lckd = 1; 
    if (pthread_mutex_trylock(&queue_mutex) == 0) q_lckd = 1; 
    if (q_lckd && !c_lckd) { QUEUE_UNLOCK; q_lckd = 0; } 
    else if (c_lckd && !q_lckd) { CRUNCH_UNLOCK; c_lckd = 0; } 

    if (c_lckd && q_lckd) { 
     printf("cr = %d, max = %d, cnt = %d\n", 
     crunching, max_crunching, queue_count(conn_queue)); 
     if (crunching < max_crunching && queue_count(conn_queue)) { 
     pthread_t tid = 
      pthread_create(
      &tid, 
      NULL, 
      crunch_conn, 
      (void *)queue_dequeue(conn_queue) 
     ); 
     crunching++; 
     } 
     CRUNCH_UNLOCK QUEUE_UNLOCK 
    } 

Cảm ơn, Chenz

Trả lời

17

Đối với pthreads nó sẽ dẫn đến hành vi không xác định. Từ trang người đàn ông dành cho pthread_mutex_unlock:

Gọi hàm pthread_mutex_unlock() với một mutex mà chuỗi cuộc gọi không giữ sẽ dẫn đến hành vi không xác định.

Các mutex khác sẽ có hành vi riêng của chúng. Như những người khác đã nói, tốt nhất là đọc hướng dẫn cho bất kỳ mutex bạn đang sử dụng.

+0

Kết quả phụ thuộc vào loại mutex theo trang người đàn ông có liên kết bạn đã cung cấp. Hành vi theo trang là 'không xác định' hoặc lỗi được trả về. –

1

Bạn không cần phải làm điều đó theo cách đó. Hãy thử điều này:

// This chunk of code makes dual locking semi-autonomous. 
int c_lckd = 0, q_lckd = 0; 
if (pthread_mutex_trylock(&crunch_mutex) == 0) c_lckd = 1; 
if (pthread_mutex_trylock(&queue_mutex) == 0) q_lckd = 1; 

if (c_lckd && q_lckd) { 
    printf("cr = %d, max = %d, cnt = %d\n", 
    crunching, max_crunching, queue_count(conn_queue)); 
    if (crunching < max_crunching && queue_count(conn_queue)) { 
    pthread_t tid = 
     pthread_create(
     &tid, 
     NULL, 
     crunch_conn, 
     (void *)queue_dequeue(conn_queue) 
    ); 
    crunching++; 
    } 

} 

if (q_lckd) { QUEUE_UNLOCK; q_lckd = 0; } 
if (c_lckd) { CRUNCH_UNLOCK; c_lckd = 0; } 

Dễ dàng theo dõi và không mạo hiểm khi cố gắng mở khóa một đoạn mở khóa.

+0

cảm ơn !, làm sạch nó một chút. Mặc dù tôi vẫn muốn được quan tâm nếu có ai biết nếu mẫu "mở khóa và mở khóa" được nêu rõ trong tiêu chuẩn POSIX. –

+0

Có, giống như tôi đã chỉnh sửa mã của mình để làm. Lấy làm tiếc! –

+0

Thậm chí nếu nó được chỉ định trong POSIX, tôi vẫn tránh làm việc đó - kinh nghiệm của tôi khiến tôi tránh xa các điều kiện góc như thế này - ngay cả khi nó được chỉ định, tôi đã bị đốt cháy quá nhiều lần. thư viện để được thoải mái thử nó. –

2

Nói chung, đối với các câu hỏi như thế này, tài liệu là nguồn thông tin tốt nhất. Các mutex khác nhau có thể hoạt động khác nhau hoặc có thể có các tùy chọn trên một mutex đơn lẻ khiến cho nó hoạt động khác nhau (ví dụ như trong trường hợp đệ quy thu được một mutex trên một chuỗi đơn).

7

Như Glen lưu ý, bạn nhận được hành vi không xác định nếu bạn cố gắng unlock một mutex đã mở khóa - đừng dùng thử. Gỡ lỗi chủ đề là đủ cứng mà không cần gọi hành vi không xác định quá.

Quan trọng hơn, phong cách mã hóa là một chút không bình thường - vì bạn sẽ không phải làm bất cứ điều gì trừ khi bạn có được cả hai ổ khóa, mã phù hợp:

if (pthread_mutex_trylock(&crunch_mutex) == 0) 
{ 
    if (pthread_mutex_trylock(&queue_mutex) == 0) 
    { 
     printf("cr = %d, max = %d, cnt = %d\n", 
       crunching, max_crunching, queue_count(conn_queue)); 
     if (crunching < max_crunching && queue_count(conn_queue)) 
     { 
      pthread_t tid; 
      int rc = pthread_create(&tid, NULL, 
           crunch_conn, (void *)queue_dequeue(conn_queue)); 
      if (rc != 0) 
      { 
       // Error recovery 
       // Did you need what was returned by queue_dequeue() 
       // to requeue it, perhaps? 
      } 
      else 
      { 
       crunching++; 
       // Do something with tid here? 
      } 
     } 
     QUEUE_UNLOCK; 
    } 
    CRUNCH_UNLOCK; 
} 

Điều này tránh sự: 'Tôi đã làm điều đó' biến ; nó cũng là ngay lập tức rõ ràng rằng miễn là các macro mở khóa làm những gì được mong đợi (và không có trường hợp ngoại lệ đi lạc hoặc setjmps xung quanh), rằng các mutexes bị khóa được mở khóa. Nó cũng tránh lãng phí năng lượng khi khóa mutex hàng đợi khi mutex không có sẵn - nhưng đó là một vấn đề nhỏ so với độ rõ nét đã thêm.

0

Mở khóa mutex chỉ nên được thực hiện trong một chuỗi chỉ khi cùng một macro bị khóa trước đó trong cùng một chuỗi. Tất cả các trường hợp khác là undvi behviour theo trang người đàn ông.

Nếu loại mutex là PTHREAD_MUTEX_DEFAULT, cố gắng đệ quy khóa kết quả mutex trong hành vi không xác định. Cố gắng mở khóa mutex nếu nó không bị khóa bởi kết quả chuỗi cuộc gọi trong hành vi không xác định. Cố gắng mở khóa mutex nếu không phải là kết quả bị khóa trong hành vi không xác định.

0

Hãy dùng thử. Đây là mã hoạt động chính xác.

// Mutex is not busy 
if(pthread_mutex_trylock(&object->mtx) == 0) { 
    if(pthread_mutex_unlock(&object->mtx)!=0) { 
     perror("ERRN: pthread_mutex_unlock:"); 
    } 
} 
// Mutex is already busy 
else { 
    if(pthread_mutex_unlock(&object->mtx)!=0) { 
     perror("ERRN: pthread_mutex_unlock:"); 
    } 
} 

// Ở thời điểm này - chúng tôi đã mở khóa chính xác mutex.

if(pthread_mutex_destroy(&object->mtx) != 0) { 
    perror("ERRN: pthread_mutex_destroy:"); 
} 
Các vấn đề liên quan