2013-04-02 18 views
5

Tôi có nhu cầu đồng bộ hóa interprocess xung quanh một phần cứng. Bởi vì mã này sẽ cần phải làm việc trên Windows và Linux, tôi đang gói với mutexes Boost Interprocess. Mọi thứ đều hoạt động tốt chấp nhận phương pháp của tôi để kiểm tra việc bỏ qua mutex. Có khả năng điều này có thể xảy ra và vì vậy tôi phải chuẩn bị cho nó.Tăng đột biến interprocess và kiểm tra từ bỏ

Tôi đã bỏ qua mutex trong thử nghiệm của mình và, đủ chắc chắn, khi tôi sử dụng scoped_lock để khóa mutex, quá trình chặn vô thời hạn. Tôi đã tìm ra cách xung quanh vấn đề này bằng cách sử dụng cơ chế timeout trên scoped_lock (vì đã dành nhiều thời gian cho Googling cho các phương thức để tính toán điều này không thực sự hiển thị nhiều, việc tăng cường không làm nhiều việc này vì các lý do về tính di động).

Nếu không có thêm ado, đây là những gì tôi có:

#include <boost/interprocess/sync/named_recursive_mutex.hpp> 
#include <boost/interprocess/sync/scoped_lock.hpp> 

typedef boost::interprocess::named_recursive_mutex MyMutex; 
typedef boost::interprocess::scoped_lock<MyMutex> ScopedLock; 

MyMutex* pGate = reinterpret_cast<MyMutex*>(new MyMutex(boost::interprocess::open_or_create, "MutexName"); 

{ 
    // ScopedLock lock(*pGate); // this blocks indefinitely 
    boost::posix_time::ptime timeout(boost::posix_time::microsec_clock::local_time() + boost::posix_time::seconds(10)); 
    ScopedLock lock(*pGate, timeout); // a 10 second timeout that returns immediately if the mutex is abandoned ????? 
    if(!lock.owns()) { 
     delete pGate; 
     boost::interprocess::named_recursive_mutex::remove("MutexName"); 
     pGate = reinterpret_cast<MyMutex*>(new MyMutex(boost::interprocess::open_or_create, "MutexName"); 
    } 
} 

đó, ít nhất, là ý tưởng. Ba điểm thú vị:

  • Khi tôi không sử dụng đối tượng thời gian chờ, và mutex bị hủy, các khối ScopedLock ctor vô thời hạn. Đó là dự kiến.
  • Khi tôi sử dụng thời gian chờ và mutex bị hủy, hàm scopedLock sẽ trả về ngay lập tức và cho tôi biết rằng nó không sở hữu mutex. Ok, có lẽ đó là bình thường, nhưng tại sao không phải là nó chờ đợi trong 10 giây tôi nói với nó quá?
  • Khi mutex không bị bỏ rơi và tôi sử dụng hết thời gian chờ, lò vi sóng ScopedLock vẫn trả về ngay lập tức, nói với tôi rằng nó không thể khóa hoặc chiếm quyền sở hữu của mutex và tôi đi qua chuyển động mutex và làm lại nó. Đây không phải là tất cả những gì tôi muốn.

Vì vậy, tôi thiếu gì khi sử dụng các đối tượng này? Có lẽ nó đang nhìn chằm chằm vào mặt tôi, nhưng tôi không thể nhìn thấy nó và vì vậy tôi yêu cầu giúp đỡ.

Tôi cũng nên đề cập rằng, vì phần cứng này hoạt động như thế nào, nếu quá trình không thể giành quyền sở hữu của mutex trong vòng 10 giây, thì mutex bị bỏ qua. Trong thực tế, tôi có thể chờ đợi ít nhất là 50 hoặc 60 mili giây, nhưng 10 giây là một số lượng "tròn" hào phóng.

Tôi đang biên soạn trên Windows 7 sử dụng Visual Studio 2010.

Cảm ơn, Andy

+2

Không liên quan đến câu hỏi của bạn, nhưng 'reinterpret_cast ' s trong ví dụ của bạn là không cần thiết (không chắc chắn lý do tại sao chúng ở đó). –

+0

@GaborMarton Tôi nghĩ rằng tôi đang sử dụng đúng chức năng remove(). Kiểm tra lại mã. Tôi đang xóa con trỏ, mà tôi đồng ý không loại bỏ mutex, nhưng sau đó tôi gọi boost :: interprocess :: named_recursive_mutex :: remove ("MyMutex"). Nếu tôi đã sử dụng không đúng cách, hãy sửa tôi. Cảm ơn –

+0

Có, bạn đã đúng, vừa xóa nhận xét của tôi và cập nhật câu trả lời của tôi. Hy vọng rằng sẽ giúp. –

Trả lời

4

Khi tôi không sử dụng các đối tượng thời gian chờ, và mutex bị hủy, các khối ctor ScopedLock vô thời hạn. Đó là dự kiến ​​

Giải pháp tốt nhất cho vấn đề của bạn sẽ là nếu tăng cường hỗ trợ cho các mutex mạnh mẽ. Tuy nhiên, Boost hiện không hỗ trợ các mutex mạnh mẽ. Chỉ có một kế hoạch để mô phỏng các mutex mạnh mẽ, bởi vì chỉ có Linux có hỗ trợ riêng về điều đó. Cuộc thi đua vẫn chỉ là kế hoạch của Ion Gaztanaga, tác giả thư viện. Kiểm tra liên kết này về việc có thể hack các mutex đột biến vào libs tăng cường: http://boost.2283326.n4.nabble.com/boost-interprocess-gt-1-45-robust-mutexes-td3416151.html

Trong khi đó, bạn có thể thử sử dụng các biến nguyên tử trong phân khúc được chia sẻ.

Ngoài ra hãy xem mục stackoverflow này: How do I take ownership of an abandoned boost::interprocess::interprocess_mutex?

Khi tôi sử dụng thời gian chờ, và mutex là bị bỏ rơi, trở về ScopedLock ctor ngay lập tức và nói với tôi rằng nó không sở hữu mutex . Ok, có lẽ đó là bình thường, nhưng tại sao không phải là nó chờ đợi trong 10 giây tôi nói với nó quá?

Điều này rất lạ, bạn không nên có hành vi này. Tuy nhiên: Khóa thời gian có thể được triển khai bằng khóa thử. Kiểm tra tài liệu này: http://www.boost.org/doc/libs/1_53_0/doc/html/boost/interprocess/scoped_lock.html#idp57421760-bb Điều này có nghĩa là việc triển khai khóa thời gian có thể ném một ngoại lệ bên trong và sau đó trả về false.

inline bool windows_mutex::timed_lock(const boost::posix_time::ptime &abs_time) 
{ 
    sync_handles &handles = 
     windows_intermodule_singleton<sync_handles>::get(); 
    //This can throw 
    winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); 
    return mut.timed_lock(abs_time); 
} 

Có thể, không thể lấy tay cầm vì mutex bị bỏ qua.

Khi mutex không bị bỏ rơi và tôi sử dụng hết thời gian chờ, ScopedLock ctor vẫn trả về ngay lập tức, nói rằng nó không thể khóa hoặc chiếm quyền sở hữu của mutex và tôi thực hiện các chuyển động loại bỏ mutex và làm lại nó. Đây không phải là tất cả những gì tôi muốn.

Tôi không chắc chắn về điều này, nhưng tôi nghĩ rằng mutex được đặt tên được thực hiện bằng cách sử dụng bộ nhớ dùng chung. Nếu bạn đang sử dụng Linux, hãy kiểm tra tệp/dev/shm/MutexName. Trong Linux, bộ mô tả tệp vẫn hợp lệ cho đến khi nó không bị đóng, bất kể bạn đã tự xóa tệp đó bằng cách, ví dụ: tăng :: interprocess :: named_recursive_mutex :: xóa.

+0

Xin lỗi vì sự chậm trễ khủng khiếp trong việc đánh dấu điều này là câu trả lời. Về cơ bản, vì tính di động trong Tăng cường, chúng tôi đã quyết định sống với "sự cố" này trong thời gian này. –

3

Kiểm tra các BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKINGBOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS biên dịch những lá cờ. Xác định biểu tượng đầu tiên trong mã của bạn để buộc các mutex interprocess time out và biểu tượng thứ hai xác định khoảng thời gian chờ.

Tôi đã giúp đưa họ vào thư viện để giải quyết vấn đề mutex bị bỏ qua. Nó là cần thiết để thêm nó do nhiều cấu trúc interprocess (như message_queue) dựa trên mutex đơn giản chứ không phải là mutex theo thời gian. Có thể có một giải pháp mạnh mẽ hơn trong tương lai, nhưng giải pháp này đã làm việc tốt cho các nhu cầu interprocess của tôi.

Tôi rất tiếc, tôi không thể giúp bạn với mã của bạn vào lúc này; một cái gì đó không hoạt động chính xác ở đó.

1

BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING không tốt lắm. Nó ném một ngoại lệ và không giúp gì nhiều. Để giải quyết các hành vi đặc biệt, tôi đã viết macro này. Nó hoạt động hoàn toàn bình thường. Trong mẫu này có tên_mutex được sử dụng. Macro tạo ra một khóa scoped với một thời gian chờ, và nếu khóa không thể được mua lại vì lý do EXCEPTIONAL, nó sẽ mở khóa nó sau đó. Bằng cách này, chương trình có thể khóa lại sau và không đóng băng hoặc gặp sự cố ngay lập tức.

#define TIMEOUT 1000 
#define SAFELOCK(pMutex) \ 
    boost::posix_time::ptime wait_time \ 
     = boost::posix_time::microsec_clock::universal_time() \ 
     + boost::posix_time::milliseconds(TIMEOUT); \ 
    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(*pMutex, wait_time); \ 
    if(!lock.owns()) { \ 
     pMutex->unlock(); } 

Nhưng ngay cả điều này không tối ưu, vì mã được khóa hiện đang chạy mở khóa một lần. Điều này có thể gây ra sự cố. Tuy nhiên, bạn có thể dễ dàng mở rộng macro. Ví dụ. chỉ chạy mã nếu lock.owns() là đúng.

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