2012-08-22 33 views
8

Tôi đã kiểm tra thư viện tăng cường (phiên bản 1.45) cho một đầu đọc/ghi văn bản. Khi tôi chạy thử nghiệm của tôi trên nó, nó có vẻ như shared_ptr là thích chủ đề đọc của tôi, tức là khi nhà văn của tôi đã cố gắng để khóa cho hoạt động của nó, nó không ngăn chặn bất kỳ lần đọc tiếp theo xảy ra.Boost shared_lock. Đọc ưa thích?

Có thể tăng cường thay đổi hành vi này không?

using namespace std; 
using namespace boost; 

mutex outLock; 
shared_mutex workerAccess; 
bool shouldIWork = true; 

class WorkerKiller 
{ 
public: 

    void operator()() 
    { 
     upgrade_lock<shared_mutex> lock(workerAccess); 
     upgrade_to_unique_lock<shared_mutex> uniqueLock(lock); 

     cout << "Grabbed exclusive lock, killing system" << endl; 
     sleep(2); 
     shouldIWork = false; 
     cout << "KILLING ALL WORK" << endl; 
    } 

private: 
}; 

class Worker 
{ 
public: 

    Worker() 
    { 
    } 

    void operator()() 
    { 
     shared_lock<shared_mutex> lock(workerAccess); 

     if (!shouldIWork) { 
      outLock.lock(); 
      cout << "Workers are on strike. This worker refuses to work" << endl; 
      outLock.unlock(); 
     } else { 
      sleep(1); 

      outLock.lock(); 
      cout << "Worked finished her work" << endl; 
      outLock.unlock(); 
     } 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
    Worker w1; 
    Worker w2; 
    Worker w3; 
    Worker w4; 
    WorkerKiller wk; 

    boost::thread workerThread1(w1); 
    boost::thread workerThread2(w2); 

    boost::thread workerKillerThread(wk); 

    boost::thread workerThread3(w3); 
    boost::thread workerThread4(w4); 

    workerThread1.join(); 
    workerThread2.join(); 
    workerKillerThread.join(); 
    workerThread3.join(); 

    return 0; 
} 

Và đây là kết quả tất cả các thời gian:

làm việc xong công việc của mình
làm việc xong công việc của mình
làm việc xong công việc của mình
làm việc hoàn thành công việc
Grabbed khóa độc quyền của mình, giết chết hệ thống
KILLING TẤT CẢ VIỆC

Yêu cầu của tôi

Nếu nhà văn cố gắng lấy khóa độc quyền, tôi muốn tất cả các thao tác đọc trước đó kết thúc. Và sau đó tất cả các hoạt động đọc tiếp theo để chặn.

+2

Bạn có thể muốn đăng một số mã kiểm tra - Kỹ năng gỡ lỗi tâm linh của tôi là yếu :-) – Bukes

Trả lời

19

Tôi là một chút muộn để câu hỏi này, nhưng tôi tin rằng tôi có một số thông tin cần thiết.

Đề xuất của shared_mutex đối với ủy ban C++, mà thư viện tăng cường dựa trên, cố tình không chỉ định API để cung cấp cho người đọc cũng như ưu tiên nhà văn. Điều này là do Alexander Terekhov đã đề xuất một thuật toán khoảng một thập kỷ trước đây là hoàn toàn công bằng. Nó cho phép hệ điều hành quyết định xem chuỗi tiếp theo có được mutex là một trình đọc hay viết hay không, và hệ điều hành là hoàn toàn không biết gì về việc liệu chuỗi tiếp theo có phải là một trình đọc hay người viết hay không.

Do thuật toán này, cần chỉ định liệu người đọc hoặc người viết có ưa thích biến mất hay không. Theo hiểu biết tốt nhất của tôi, các thư viện tăng cường hiện nay (tăng 1.52) được triển khai bằng thuật toán công bằng này.

Thuật toán Terekhov bao gồm mutex đọc/ghi bao gồm hai cổng: gate1 và gate2. Chỉ có một luồng tại một thời điểm có thể đi qua mỗi cổng. Các cổng có thể được thực hiện với một mutex và hai biến điều kiện.

Cả độc giả và nhà văn đều cố gắng đi qua cổng 1. Để đi qua cổng 1, phải đúng là một luồng ghi chú hiện không nằm trong cổng 1. Nếu có, luồng cố gắng đi qua khối gate1.

Khi chuỗi trình đọc đi qua cổng 1, nó đã đọc quyền sở hữu của mutex.

Khi chuỗi ghi đi qua cổng 1, nó cũng phải đi qua cổng 2 trước khi có quyền ghi quyền sở hữu của mutex. Nó không thể đi qua cổng 2 cho đến khi số lượng độc giả bên trong cổng1 giảm xuống 0.

Đây là một thuật toán công bằng vì khi chỉ có 0 hoặc nhiều người đọc bên trong cổng 1, hệ điều hành sẽ xem liệu chuỗi tiếp theo có được bên trong cổng 1 hay không. Một nhà văn trở thành "ưu tiên" chỉ sau khi nó đã đi qua cổng 1, và do đó tiếp theo xếp hàng để có được quyền sở hữu của mutex.

Tôi đã sử dụng ví dụ của bạn được biên soạn dựa trên việc triển khai ví dụ về những gì cuối cùng đã trở thành shared_timed_mutex trong C++ 14 (với các sửa đổi nhỏ đối với ví dụ của bạn). Mã dưới đây gọi nó là shared_mutex là tên nó có khi nó được đề xuất.

tôi có các kết quả sau (tất cả với cùng thực thi):

Đôi khi:

Worked finished her work 
Worked finished her work 
Grabbed exclusive lock, killing system 
KILLING ALL WORK 
Workers are on strike. This worker refuses to work 
Workers are on strike. This worker refuses to work 

Và đôi khi:

Worked finished her work 
Grabbed exclusive lock, killing system 
KILLING ALL WORK 
Workers are on strike. This worker refuses to work 
Workers are on strike. This worker refuses to work 
Workers are on strike. This worker refuses to work 

Và đôi khi:

Worked finished her work 
Worked finished her work 
Worked finished her work 
Worked finished her work 
Grabbed exclusive lock, killing system 
KILLING ALL WORK 

tôi tin rằng về mặt lý thuyết có thể cũng có được các kết quả đầu ra khác, mặc dù tôi đã không xác nhận thực nghiệm đó.

Trong sự quan tâm của tiết lộ đầy đủ, đây là mã chính xác tôi thực hiện:

#include "../mutexes/shared_mutex" 
#include <thread> 
#include <chrono> 
#include <iostream> 

using namespace std; 
using namespace ting; 

mutex outLock; 
shared_mutex workerAccess; 
bool shouldIWork = true; 

class WorkerKiller 
{ 
public: 

    void operator()() 
    { 
     unique_lock<shared_mutex> lock(workerAccess); 

     cout << "Grabbed exclusive lock, killing system" << endl; 
     this_thread::sleep_for(chrono::seconds(2)); 
     shouldIWork = false; 
     cout << "KILLING ALL WORK" << endl; 
    } 

private: 
}; 

class Worker 
{ 
public: 

    Worker() 
    { 
    } 

    void operator()() 
    { 
     shared_lock<shared_mutex> lock(workerAccess); 

     if (!shouldIWork) { 
      lock_guard<mutex> _(outLock); 
      cout << "Workers are on strike. This worker refuses to work" << endl; 
     } else { 
      this_thread::sleep_for(chrono::seconds(1)); 

      lock_guard<mutex> _(outLock); 
      cout << "Worked finished her work" << endl; 
     } 
    } 
}; 

int main() 
{ 
    Worker w1; 
    Worker w2; 
    Worker w3; 
    Worker w4; 
    WorkerKiller wk; 

    thread workerThread1(w1); 
    thread workerThread2(w2); 

    thread workerKillerThread(wk); 

    thread workerThread3(w3); 
    thread workerThread4(w4); 

    workerThread1.join(); 
    workerThread2.join(); 
    workerKillerThread.join(); 
    workerThread3.join(); 
    workerThread4.join(); 

    return 0; 
} 
+0

Vâng tôi vừa quay lại câu hỏi này để đăng câu trả lời tương tự này. Bạn thực sự là chính xác. Boost sử dụng một triển khai công bằng ngay bây giờ và bạn không thể thực sự kiểm soát cái nào được chọn. Cảm ơn bạn rất nhiều vì đã giải thích chi tiết. – anoneironaut

+0

Giấy bloomington dường như bị thiếu trong trang web mới tại http://howardhinnant.github.io/. Tôi không biết cách sửa cái đó :) – sehe

1

Một tìm kiếm google của "đói khóa thúc đẩy chia sẻ" bật lên liên kết này:

Dường như "nâng cấp" có thể là chìa khóa. Xem thêm:

+0

Hi Paul. Tôi đã xem những bài viết đó. Họ đã đọc rất nhiều nhưng tôi vẫn còn một chút mất mát lớn về việc có hay không tôi có thể thiết lập những mutexes như Viết ưa thích. Bài viết cuối cùng có vẻ phác thảo một mô hình mutex mà tăng là tương tự quá nhưng có sự khác biệt chính. Trong mô hình đó chắc chắn là viết được ưa thích. Nhưng trong tăng cường nó có vẻ là hệ điều hành cụ thể? Tôi cũng tìm thấy thông tin này trong tài liệu 1.35: http://www.boost.org/doc/libs/1_34_0/doc/html/thread/concepts.html#thread.concepts.read-write-scheduling-policies.inter -lớp học. Ngoài ra tôi đã cố gắng nâng cao sự ưu tiên của nhà văn. – anoneironaut

+0

@HowardHinnant Tôi đã cố gắng [sửa liên kết này] (http://stackoverflow.com/posts/12082441/revisions). Có lẽ bạn có thể xem lại nó – sehe

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