您需要創建對象的總體排序(在這種情況下爲Account對象),然後根據總排序始終將它們鎖定在相同的順序。您可以決定將它們鎖定的順序,但最簡單的方法是首先鎖定總排序中第一個的順序,然後鎖定另一個。
例如,假設每個帳戶都有一個帳號,它是唯一的*整數。 (*表示沒有兩個賬號具有相同的號碼)然後,您可以先鎖定小號賬號。使用你的例子:
void transaction (Account from, Account to, double amount)
{
mutex first_lock, second_lock;
if (acct_no(from) < acct_no(to))
{
first_lock = get_lock(from);
second_lock = get_lock(to);
}
else
{
assert(acct_no(to) < acct_no(from)); // total ordering, so == is not possible!
assert(acct_no(to) != acct_no(from)); // this assert is essentially equivalent
first_lock = get_lock(to);
second_lock = get_lock(from);
}
acquire(first_lock);
acquire(second_lock);
withdraw(from, amount);
deposit(to, amount);
release(second_lock);
release(first_lock);
}
因此,下面的例子,如果checking_account有帳戶號碼。 1和savings_account有帳戶號碼。 2,transaction (savings_account, checking_account, 500);
將首先鎖住checking_account,然後儲蓄帳戶,transaction (checking_account, savings_account, 300);
也會先鎖住checking_account,然後鎖定savings_account。
如果您沒有帳號(例如您使用Foo類而不是類Account),那麼您需要找到其他方法來確定總排序。如果每個對象都有一個名稱(字符串),則可以進行字母比較以確定哪個字符串是「較少」的。或者,您可以使用任何其他類型的「>和<」。
但是,值對於每個對象都是唯一的非常重要!如果兩個對象在您測試的任何字段中具有相同的值,則它們在排序中的相同位置。如果發生這種情況,那麼這是一種「部分排序」而不是「總排序」,並且對此鎖定應用程序進行總排序非常重要。
如有必要,您可以組成一個「關鍵值」,該關鍵值是一個任意數字,並不代表任何意義,但對於該類型的每個對象都是唯一的。每個對象在創建時都會分配一個新的唯一值。
另一種選擇是將該類型的所有對象保留在某種列表中。然後,他們的名單職位將把他們放在一個完整的排序中。 (坦率地說,「關鍵值」方法更好,但爲了應用程序邏輯的目的,某些應用程序可能已將對象保存在列表中,因此您可以利用現有列表。)但是,請注意,當您使用此方法時,最終不會像O(n)時間(而是像其他方法*那樣使用O(1))來確定哪一個在總排序中排在第一位。 (*如果你使用一個字符串來確定總排序,那麼它並不是真的O(1),但它與字符串的長度成線性關係,並且保持這些字符串的對象的數量不變。但是,根據您的應用程序,字符串長度可能比數字對象合理得多。)
沒有明顯的互斥體概念,允許以您擁有它的方式進行分配。互斥體擁有某種「獨特的所有權」。此外,你真的應該更努力不要混淆互斥和鎖定。 –