Evet, kilit hiyerarşileri kilitlenmeyi etkili bir şekilde önleyebilir; Elbette programınız için bir hiyerarşi tanımlayabiliyor olsanız da (özellikle eklentilerin varlığında) tamamen başka bir konu.
temel bloklar basittir:
- Her muteks bir seviyeye sahip olmalıdır (ya derleme zamanında belirlenen veya çalışma zamanı)
- sadece hiç artan Muteksleri veya azalan düzeyi (edinmeniz gerekmektedir Her iş parçacığı bir kere karar verin)
Umarım adalet fikrini uygulayabilirim, lütfen örnek çizimi bir çizimin altında düşünün; hiçbir zaman derlenmiş/test edilmemiştir.
Temel muteksin:
template <typename Mutex, size_t Level>
class HierarchicalMutex {
public:
friend class LevelManager;
void lock() {
LevelManager::Lock(*this);
}
void unlock() {
LevelManager::Unlock(*this);
}
private:
size_t previous;
Mutex mutex;
}; // class HierarchicalMutex
template <typename Mutex, size_t Level>
size_t level(HierarchicalMutex<Mutex,Level> const&) { return Level; }
LevelManager
rolü olduğu seviye geçişleri doğru sırayla gerçekleşmesi sağlamak için basitçe. tekmeler için
class LevelManager {
public:
//
// Single Mutex locking
//
template <typename M>
static void Lock(M& m) {
m.previous = LevelUp(level(m));
m.mutex.lock();
}
template <typename M>
static void Unlock(M& m) {
m.mutex.unlock();
LevelDown(level(m), m.previous);
}
//
// Multiple Mutexes Group Locking
//
// Note: those should expose a "size_t level(M const&)" function,
// and calls to lock/unlock should appropriately call
// this manager to raise/lower the current level.
//
// Note: mutexes acquired as a group
// should be released with the same group.
//
template <typename M>
static void Lock(std::array_ref<M*> mutexes) { // I wish this type existed
using std::begin; using std::end;
auto begin = begin(mutexes);
auto end = end(mutexes);
end = std::remove_if(begin, end, [](M const* m) { return m == 0; });
if (begin == end) { return; }
Sort(begin, end);
size_t const previous = LevelUp(level(*std::prev(end)));
for (; begin != end; ++begin) {
begin->previous = previous;
begin->mutex.lock();
}
}
template <typename M>
static void Unlock(std::array_ref<M*> mutexes) {
using std::begin; using std::end;
auto begin = begin(mutexes);
auto end = end(mutexes);
end = std::remove_if(begin, end, [](M const* m) { return m == 0; });
if (begin == end) { return; }
Sort(begin, end);
std::reverse(begin, end);
for (auto it = begin; it != end; ++it) { it->mutex.unlock(); }
LevelDown(level(*begin), begin->previous);
}
private:
static __thread size_t CurrentLevel = 0;
template <typename It>
static void Sort(It begin, It end) {
using Ref = typename std::iterator_traits<It>::const_reference;
auto const sorter = [](Ref left, Ref right) {
return std::tie(level(left), left) < std::tie(level(right), right);
};
std::sort(begin, end, sorter);
}
static size_t LevelUp(size_t const to) {
if (CurrentLevel >= to) { throw LockHierarchyViolation(); }
CurrentLevel = to;
}
static void LevelDown(size_t const from, size_t const to) {
if (CurrentLevel != from) { throw LockHierarchyViolation(); }
CurrentLevel = to;
}
}; // class LevelManager
, tek bir çekimde aynı seviyede katları kilitleri kilitlemek imkanı uyguladı.
benim cevap belirttiğimiz gibi kilitlenme kaçınarak kimse anahtar ve ettik basit bandaj yoktur anladım. Tasarım sürecinde bunu önlemek için çok daha iyi. Özel durumun nedir? –
@Platinum Azure: Eski ve büyük bir kod tabanında kilitlenme sorunları için çözümler arıyorum. – StackedCrooked
O zaman hiçbir şeyim yok üzgünüm. :-( –