2017-06-12 123 views
0

我目前正在研究信號量和互斥實際如何工作,並遇到以下問題。信號量等待()在多核

我們假設我們在CPU上有兩個內核。我們有兩個進程,每個核心都運行一個進程。現在我們正在呼籲兩個內核的wait()調用,因爲我們希望進入一個關鍵部分:如果兩個內核並行執行代碼

wait(){ 
    while(s.value <= 0) 
    // busy waiting 
    s.value--; 
} 

,初始信號值是1,無論閱讀while循環語句,其結果爲false(自s = 1)。這意味着,幾乎在同一時間減少信號量,其結果爲s = -1。現在,兩個流程同時進入他們的關鍵部分,而這在互斥方面是不可能的。

我得到什麼錯誤?

感謝您的澄清。

+1

非零計數和減量的等待通常在操作系統的內核中進行處理,方式是使檢查和遞減爲原子操作。 – rcgldr

回答

1

您可以使用java和其他語言同步來同步代碼塊或函數,並避免此類問題,因爲當一個線程正在執行同步方法或塊時,調用同步方法的所有其他線程或者阻塞(掛起執行)直到第一個線程完成。

1

正如你已經發現的那樣,這些不是簡單的用戶空間函數 - 它會非常棘手(不可能?)讓你自己實現一個信號量或互斥量,而不使用內核提供的函數。

例如,在Linux上您有:


你有概念,正確的,但兩個操作(檢查和INC/dec)需要在「原子」的方式進行 - 簡單地說,這意味着它們作爲無法拆分的一個操作發生(在Linearizability上閱讀)。

此外,值得注意的是,你已經實現了一個「忙循環」,它與操作系統工作時是一個壞主意因爲你是剝奪了其他任務/從CPU時間,提高電力使用的過程,而這樣做沒有實際的工作 - 上面提到的功能將「」與0%的CPU使用率,而你的將「」與100%的CPU使用率,如果有機會。


你將有更多的運氣試圖「玩」這樣的概念在單一內核上運行時,(你可以限制你的應用程序執行,以單核 - 看sched_setaffinity()

然而,即使你會發現你很難控制你的程序是否在不好的時間安排好,導致你的示例應用程序以完全相同的方式中斷。通過撥打sched_setscheduler()SCHED_FIFO可能會進一步提高正確操作的機會,儘管我還沒有親身體驗過這方面的經驗(ref,ref)。

無論哪種方式,這不可能是100%可靠的,而內核支持的功能應該是。


如果你爲它,那麼最好的方式與在自己的職能的實現細節發揮將是實現一個非常基本的循環調度(不中斷的任務),並運行它在微觀或單一線程中。

1

使用信號量的內置函數可能會更好。要等待使用pthreads庫,您需要使用pend()函數,並且要使信號量可用,您可以使用post()函數。

pend將等到s的值大於0.然後它會自動遞減s的值,然後繼續向前。當然,如何正確實施取決於圖書館。它可能看起來像這樣:

sem_wait(){ 
    // Make a kernel function call to guarantee that the following code is atomic 
    enter_critical_section(); 
    // Test the semaphore value. If it is positive, let the code continue. 
    int sem_val = s.value; 
    s.value--; 
    if (sem_val > 0) { 
     exit_critical_section(); 
     return; 
    } 
    else { 
    // At this point we know the semaphore value is negative, so it's not available. We'd want to block the caller and make a context switch to a different thread or task. 
    ... // Put the current thread on list of blocked threads 
    ... // Make a context switch to a ready thread. 
    } 
    // When the semaphore is made available with a sem_post() function call somewhere else, there will eventually be a context switch back to this (blocked) thread. Simply exit the critical section, return back to the calling function, and let the program execute normally. 
    exit_critical_section(); 
} 

這段代碼實際上是基於一個爲類實現的RTOS。每個實現看起來都會非常不同,而且我還沒有在這裏展示很多,但它應該給你一個關於它如何工作的基本概念。

最後,在您的假設情況下,您提到了共享單個信號量的2個獨立進程。這是可能的,你只需要做出正確的函數調用來使信號量在進程之間共享。