2011-07-23 32 views
11

Tôi cần hai chuỗi để tiến hành theo mẫu "tick tock". Khi implmented với một semaphore này có vẻ tốt đẹp:Sử dụng mutex làm semaphore?

Semaphore tick_sem(1); 
Semaphore tock_sem(0); 

void ticker(void) 
{ 
    while(true) 
    { 
     P(tick_sem); 
     do_tick(); 
     V(tock_sem); 
    } 
} 

void tocker(void) 
{ 
    while(true) 
    { 
     P(tock_sem); 
     do_tock(); 
     V(tick_sem); 
    } 
} 

Tuy nhiên, nếu tôi làm điều tương tự với một mutex (đó là về mặt kỹ thuật một semaphore nhị phân), nó có một mã mùi kỳ lạ.

std::mutex tick_mutex; 
std::mutex tock_mutex; 
tock_mutex.lock(); 

void ticker(void) 
{ 
    while(true) 
    { 
     tick_mutex.lock(); 
     do_tick(); 
     tock_mutex.unlock(); 
    } 
} 

void tocker(void) 
{ 
    while(true) 
    { 
     tock_mutex.lock() 
     do_tock(); 
     tick_mutex.unlock(); 
    } 
} 

Tôi nghĩ rằng mùi là một mutex không có nghĩa là truyền tải thông tin đến một chủ đề khác. (Ủy ban tiêu chuẩn C++ 11 thêm giả mạo không try_lock để đánh bại việc chuyển thông tin bất ngờ; §30.4.1/14.) Có vẻ như mutexes có nghĩa là đồng bộ hóa truy cập vào một biến, sau đó có thể chuyển tải thông tin đến một luồng khác.

Cuối cùng, khi được triển khai với std::condition_variable, có vẻ đúng nhưng phức tạp hơn (biến tick_vs_tock, mutex và biến điều kiện). Tôi đã bỏ qua việc triển khai cho ngắn gọn, nhưng nó thực sự thẳng về phía trước.

Giải pháp mutex có ổn không? Hay có điều gì đó không đúng với nó?

Có cách nào tốt để giải quyết vấn đề đánh dấu/tock của tôi mà tôi chưa từng nghĩ đến?

+0

BTW: vấn đề này chỉ phát sinh vì C++ 0x không có 'std :: semaphore' và giải pháp' std :: mutex' đôi phức tạp hơn giải pháp 'std :: condition_variable'. –

+3

(Tại sao) nó thậm chí còn hợp lệ để 'mở khóa()' một mutex trong một chuỗi mà hiện tại không giữ nó? –

+0

@Steve thực sự là câu hỏi hay (gợi ý, gợi ý, di chuyển, di chuyển). –

Trả lời

10

Một Mutex không đơn giản chỉ là một semaphore nhị phân, nó cũng có giới hạn mà chỉ có chủ đề khóa được phép mở khóa nó.

Bạn đang vi phạm quy tắc đó.

Edit:

Từ MSDN:

Chức năng ReleaseMutex thất bại nếu tiểu trình đang gọi không sở hữu các đối tượng mutex.

Từ một số trang web mà google bật lên cho pthread_mutex_unlock:

Các pthread_mutex_unlock() chức năng có thể thất bại nếu:

EPERM Các chủ đề hiện tại không sở hữu mutex.

Và bạn sẽ tìm thấy tương tự trên các triển khai mutex khác. Nó có ý nghĩa bởi vì một mutex có nghĩa vụ phải bảo vệ quyền truy cập của một luồng vào một tài nguyên, vì vậy một luồng khác sẽ không thể mở khóa nó.

+0

Theo nhận xét của Steve. Đó thực sự là một quy tắc? Đó chắc chắn là một ý tưởng hay. –

+0

@deft - Tôi nghĩ rằng nó phụ thuộc vào việc thực hiện mutex, phụ thuộc vào hệ thống. Nó thường không phải là một ý tưởng tốt để mở khóa mutex của người khác, ngay cả khi nó được cho phép bởi hệ thống. – littleadv

+0

@deft_code: Tôi chưa đọc phần mutex của FDIS, nhưng tôi sẽ ngạc nhiên nếu nó * không phải là * quy tắc. Mutexes có một chủ sở hữu, đó là một phần của định nghĩa cơ bản của họ như một công cụ đồng bộ hóa. –

9

Vì bạn có trường hợp sử dụng semaphore, tôi cho rằng bản sửa lỗi là có thể di chuyển implement one using a mutex and a condition variable.

Điều này có thể không đặc biệt hiệu quả (vì nó sẽ sử dụng cặp mutex/condvar trên mỗi semaphore), nhưng bạn có thể chuyển sang triển khai thay thế trên hệ thống có ẩn dụ riêng của chúng (chẳng hạn như Posix và Windows).

Dường như semaphores are "too error-prone". Với tất cả sự tôn trọng của Boost, tôi nghĩ rằng ít nhất một số người trong chúng ta có thể quản lý. Chắc chắn bạn có thể buộc mình vào knots trying to do complicated things with multiple semaphores, và họ là một công cụ khá thấp. Nhưng khi họ đúng, không sao cả.

+0

Tôi đồng ý rằng điều "quá dễ bị lỗi" là lạ. Mutexes có thể dễ bị lỗi. Vì vậy, có thể một cái búa. – asveikau

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