讓我們假設該服務器採取的一些時間不可忽略量的處理請求。然後,如果請求速度足夠快,則會在等待其中一個服務器處理先前請求時調用SendRequest
。
作爲一個設計師,你有兩個選擇。
- 如果服務器可以同時處理多個請求,那麼你什麼也不做。
- 如果一個服務器只能一次處理一個請求,那麼你就需要在代碼中執行某種同步。
在情況2中,由於您已經在服務器上有鎖,因此您可以交換它們而不產生分支。
對於案例1,爲什麼不能做到以下幾點:
std::mutex my_mutex;
...
// Select the server
server* selected = NULL;
my_mutex.lock();
selected = &primary;
my_mutex.unlock();
// Let the selected server process the message.
bool success = selected->process();
// If there was a primary failure, see if we can try the backup.
if (!success) {
my_mutex.lock();
if (selected == &primary) {
selected = &backup;
}
my_mutex.unlock();
// Now try again
success = selected->process();
// If the backup was used successfully, swap the primary and backup.
if (success) {
my_mutex.lock();
if (selected == &backup) {
backup = primary;
primary = selected;
}
my_mutex.unlock();
}
}
但是這可能有一些問題。比如說,第一條信息主要失敗,但其他信息成功。如果sendRequest將()由3個不同的線程調用在同一時間,則可以有以下幾種:
- 線索1 - 發送具有初級
- 線程2 - 原發性
- 線程3發送 - 發送與伯
- 線程1 - 失敗,發送具有備份
- 線程2 - 初級成功
- 線程1 - 備份成功
- 線程1 - 互換主和備份
- 線程3 - 舊的主(新的備份)成功
- 線程3 - 交換主用和備用
如果消息不斷傳來速度不夠快,有可能保持這種狀態,你保持交換主要和備份。該條件可以解決沒有掛起消息的時刻,然後主設備和備份設置將被設置,直到出現另一個故障。
也許一個更好的辦法是永不掉,但有一個更好的選擇方法。例如:
...
// Select the server
server* selected = NULL;
selected = &primary;
if (!primary.last_message_successful) {
// The most recent attempt made with primary was a failure.
if (backup.last_message_successful) {
// The backup is thought to be functioning.
selected = &backup;
}
}
// Let the selected server process the message.
// If successful, process() will set the last_message_successful boolean.
bool success = selected->process();
// If there was a failure, try the other one.
if (!success) {
if (&primary == selected) {
selected = &backup;
} else {
selected = &primary;
}
}
// Try again with the other one.
selected->process();
在本例中,鎖是沒有必要的。主要將被使用,直到它失敗。然後將使用備份。如果同時處理其他消息,則可能會導致主服務器再次可用,在這種情況下,它將被使用。否則,將使用備份直到失敗。如果兩者都失敗了,它們都會被嘗試,首先是主要的,然後是備份。
如果您使用語言或系統或特定內容標記此標記,您可能會獲得更多幫助。 –