2012-10-25 43 views
6

Tôi có một cá thể lớp được sử dụng bởi một số lớp khác trong các chủ đề khác để giao tiếp.Điều gì có thể gây ra bế tắc của một khóa đọc/ghi nhiều lần?

lớp này sử dụng một đầu đọc mỏng/khóa nhà văn (WinAPI của SRWLOCK) như là một đối tượng đồng bộ hóa và một vài lớp helper RAII để thực sự khóa/mở khóa điều:

static unsigned int readCounter = 0; 

class CReadLock 
{ 
public: 
    CReadLock(SRWLOCK& Lock) : m_Lock(Lock) { InterlockedIncrement(&readCounter); AcquireSRWLockShared(&m_Lock); } 
    ~CReadLock() {ReleaseSRWLockShared(m_Lock); InterlockedDecrement(&readCounter);} 

private: 
    SRWLOCK& m_Lock; 
}; 

class CWriteLock 
{ 
public: 
    CWriteLock(SRWLOCK& Lock) : m_Lock(Lock) { AcquireSRWLockExclusive(&m_Lock); } 
    ~CWriteLock() { ReleaseSRWLockExclusive(&m_Lock); } 

private: 
    SRWLOCK& m_Lock; 
}; 

Vấn đề là điều bế tắc toàn bộ mọi lúc. Khi tôi tạm dừng chương trình bế tắc, tôi thấy:

  • một sợi bị kẹt trong AcquireSRWLockExclusive();
  • hai chủ đề bị kẹt trong AcquireSRWLockShared();
  • readCounter toàn cầu được thiết lập để 3.

Con đường tôi nhìn thấy nó, cách duy nhất để điều này xảy ra là destructor CReadLock sơ thẩm chưa được gọi là bằng cách nào đó một nơi nào đó khóa là vĩnh viễn bị mắc kẹt. Tuy nhiên, cách duy nhất để điều này xảy ra (theo như tôi biết) là vì một ngoại lệ đã bị ném. Nó không phải. Tôi đã kiểm tra.

Điều gì có thể là vấn đề? Làm thế nào tôi nên đi về sửa chữa (hoặc ít nhất là định vị lý do) điều này?

Trả lời

9

Bạn đang sử dụng Đọc khóa theo cách đệ quy?

void foo() 
{ 
    CReadLock rl(m_lock); 
    ... 
    bar(); 
} 
void bar() 
{ 
    CReadLock rl(m_lock); 
    ... 
} 
void baz() 
{ 
    CWritedLock rl(m_lock); 
    ... 
} 

nếu foo()baz() được gọi cùng một lúc bạn có thể nhận bế tắc:

1. (Thread A) foo locks 
2. (Thread B) baz asks to create write lock now all read locks would block until all are released - waits. 
3. (Thread A) bar tries to lock and waits because there is pending write lock 

Thực tế là bạn đã 2 chủ đề bị mắc kẹt trên đọc khóa và đọc Khóa truy cập là 3 mà rất có thể cho thấy rằng bạn có một đệ quy trong một trong những ổ khóa - tức là một sợi đã cố gắng để có được khóa đọc hai lần.

+0

Không nên 'bar' chỉ nhận khóa? Ngoài ra nó có thể có thể bế tắc nếu 'foo' gọi' baz' (Không biết khóa có đệ quy) – Lol4t0

+0

Không cần thiết, 'GetireSRWLockShared' của Win32 API không được đệ quy ** không giống như 'pthread_rwlock_rdlock' hoặc' EnterCriticalSection' của POSIX – Artyom

+0

Bạn có thể chứng minh rằng 'baz yêu cầu tạo khóa ghi bây giờ tất cả các khóa đọc sẽ chặn cho đến khi tất cả được phát hành - chờ đợi.'? Bởi vì MSDN [nói] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937%28v=vs.85%29.aspx): 'Không có gì đảm bảo về thứ tự trong đó chủ đề yêu cầu quyền sở hữu sẽ được cấp quyền sở hữu; Ổ khóa SRW không công bằng hay FIFO. ' – Lol4t0

3
one thread stuck in AcquireSRWLockExclusive(); 
two threads stuck in AcquireSRWLockShared(); 
readCounter global is set to 3. 

Vâng, theo như tôi có thể đọc từ đó, bạn có một luồng đang giữ khóa đọc hiện tại, một chuỗi ghi chờ khóa đọc đó được phát hành và hai chuỗi đã đọc đang chờ chuỗi ghi đó lấy và nhả khóa.

Nói cách khác, bạn có một chuỗi chỉ đọc lơ lửng, không bị hủy hoại, giống như bạn tự nói. Thêm gỡ lỗi in để destructor và constructor.

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