[英]Standard atomic operations of semaphores
我是自學C,這是信號量的練習題:
回想一下,計數信號量S是一個整數變量,只能通過兩個標准原子操作P(探測)和V(信號)來控制,如圖所示:
/*The probe or wait operation */ P(S) { while(S <= 0); // do nothing S--; } /*The signal operation */ V(S) { S++; }
計數信號量的值可以超過不受限制的整數域(即,信號量可以包含任意值),而二進制信號量的值只能是0或1.顯示如何僅使用二進制來實現計數信號量信號量和普通(即可搶占)機器指令和數據結構。
為P和V操作提供偽代碼。
我在網上找到了相關的答案:
struct semaphore {
int value;
queue L; // l list of processes
}
wait(S) {
if(s.value > 0){
s.value = s.value - 1;
} else {
add this process to S.L;
block;
}
}
signal(S){
if(S.L != EMPTY) {
remove a process P from S.L;
wakeup(P);
} else {
s.value = s.value + 1;
}
}
但說實話,我不知道它在做什么。 我真的很感激有人可以解釋答案,或者可能用偽代碼演示如何回答這個問題。
展示如何僅使用二進制信號量和普通(即可搶占的)機器指令和數據結構來實現計數信號量。
二進制信號量非常像互斥體(存在一些顯着的差異,但出於這個問題的目的,假設它們是等價的),因此您可以實現具有計數器和二進制信號量的數據結構的通用信號量。 二進制信號量用於同步對計數器的訪問。
信令可以通過獲取二進制信號量(即等待信號量),遞增計數器然后發信號通知二進制信號量(釋放鎖定)來實現。
通過重復獲取鎖(等待二進制信號量),測試計數器是否大於0以及釋放鎖來實現等待。 如果計數器確實大於0,那么這意味着我們得到了一個位置,所以我們遞減計數器並返回。 請注意,這必須是原子的:我們不能釋放二進制信號量並在之后遞減計數器,因為這會打開一個時間窗口,其中另一個線程可能會錯誤地看到相同的東西並同時獲取我們在該行中的位置。 因此,二進制信號量用於原子測試計數器並減少它(如果它大於0)。
假設二進制信號量具有類型bin_sem_t
。 這里有一些代碼可以說明這一點。 數據結構如下:
/* A semaphore implemented with a binary semaphore */
struct semaphore {
bin_sem_t sem; /* Controls concurrent access to the counter */
int counter;
};
信號:
void sem_signal(struct semaphore *semaphore) {
/* We use the binary semaphore to atomically increment the counter */
wait(semaphore->sem);
semaphore->counter++;
signal(semaphore);
}
等候:
void sem_wait(struct semaphore *semaphore) {
int acquired = 0;
/* Here we use the binary semaphore to atomically test and
* decrement the counter
*/
while (!acquired) {
wait(semaphore->sem);
if (semaphore->counter > 0) {
semaphore->counter--;
acquired = 1;
}
signal(semaphore->sem);
}
}
一些重要的說明:
sem_signal()
或sem_wait()
任何調用之前初始化二進制信號量。 說實話,我不認為你在網上找到的答案是正確的,它似乎沒有在櫃台或進程隊列上進行任何形式的同步。 因此,在實現同步原語時,它無法解決其中一個核心問題:顯然,它們必須是線程安全的!
這看起來也不正確:
計數信號量的值可以超過不受限制的整數域(也就是說,信號量可以保持任意值)[...]
首先,通用信號量通常不能具有負值,它總是大於或等於0.其次,計數器的值有一個明顯的上限; 電腦沒有無限的記憶。 在Linux中,信號量可以容納的SEM_VALUE_MAX
在semaphore.h
定義為SEM_VALUE_MAX
。
所以請注意這些在線教程,其中大部分都是不准確的,缺乏細節,或者只是完全錯誤。 你應該從一本好書中學習。 我通常喜歡在UNIX環境中推薦高級編程 ,雖然它不是專門針對線程的,但是它深入介紹了同步原語。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.