計算機中以二進位作為資料的表示方式和儲存方式,符號則另存為另外一個bit來表示正負數,比如說:
10000001 -> -1
00000001 -> +1
最前面的1或0作為正負數的標示,後面則是數值的大小
此表示法的缺點就是0會有兩種表示方法,
10000000 -> -0
00000000 -> +0
並且在近行加法或減法時,加法時需要進行進位(carry),減法時需要進行借位(borrow),在現實生活中很難被實現,所以現今計算機不使用此編碼方式
一補數實際上只是將二進位中的1變成0,0變成1,讓負數可以用來作為減法的方法,比如說原本為:
1-2=-1
變成
1+(-2)=-1
從二進位的角度來看
所以從以上運算可以看到上面是沒有進位的一補數運算,也看到一補數運算可以讓原本的減法變成加法,這樣可以讓正負號不需要多出一個bit來儲存它,下面則是需要進位的一補數算法
此表示法的的缺點在於遇到需要進位時要進行循環進位,但比起符號與值每個加法和減法都需要去比較是否要進位和借位簡單許多,但是0的表示法仍然有兩種,0000和1111
二補數就是一補數再加上1,並且計算方式為最高位元為負數,其他皆為正數,這樣即可解決0有兩種表示方法的問題
參考資訊
首先先了解三種bit-wise operator:|,&,^
| (OR) 運算子
input 1 | input 2 | output |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
& (AND) 運算子
input 1 | input 2 | output |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
^ (XOR) 運算子
input 1 | input 2 | output |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
深入理解二進位所編成的ascii碼後,發現我們可以使用bit-wise運算子來簡單的將大小轉換
以E轉換成e作為例子:
上表中E為69,e為101,轉為二進位
E = 0100 0101
e = 0110 0101
兩者差32,回去查表,32代表著空格(' '),接著再加入bit-wise運算子看看會發生什麼
參考資訊
Question:
livelock?
promela?
ABA-problem?
主要概念為將每一個動作區分為沒辦法再分割的動作,常見的 Atomics Operations 有 Read-modify-write,Test-and-Set,Fetch-and-add 和 Compare-and-Swap
Compare-and-Swap
Test-and-Set
volatile
關鍵字和 Atomic operation 的關係volatile
到底是什麼?直接看 c 語言規格書 來看看 volatile
到底在幹嘛
Accessing a volatile object, modifying an object, modifying a file, or calling a function
that does any of those operations are all side effects, which are changes in the state of
the execution environment. Evaluation of an expression may produce side effects. At
certain specified points in the execution sequence called sequence points, all side effects
of previous evaluations shall be complete and no side effects of subsequent evaluations
shall have taken place.
在使用 volatile
時,需要注意的是會產生的 side effect,也就是說在執行的情況下遭到了未預期的改變,而 volatile
的作用在取原本的數值並且抑制編譯器的優化。在 Why the "volatile" type class should not be used 中也有提到:
The key point to understand with regard to volatile is that its purpose is
to suppress optimization, which is almost never what one really wants to
do. In the kernel, one must protect shared data structures against
unwanted concurrent access, which is very much a different task. The
process of protecting against unwanted concurrency will also avoid almost
all optimization-related problems in a more efficient way.
Like volatile, the kernel primitives which make concurrent access to data
safe (spinlocks, mutexes, memory barriers, etc.) are designed to prevent
unwanted optimization. If they are being used properly, there will be no
need to use volatile as well. If volatile is still necessary, there is
almost certainly a bug in the code somewhere. In properly-written kernel
code, volatile can only serve to slow things down.
抑制編譯器的優化從來不是我們想要的事情,所以從核心的 shared memory 中資料的讀取應該要有較為有效率的動作比如說 spinlock,mutex 之類的而不是使用 volatile
。
Process 由作業系統所提供,裡面的資訊包含以下幾點:
Threads 則是存在於 Process 中,並且視為一個獨立的控制流程,可以被作業系統排程,其原因為擁有以下幾點:
在同一個 Process 中可以擁有多個 threads,而所有的 threads 可以共享同個 Process 的資源,並且執行在同一個 Process 中。
從一個 thread 中執行任務改變共享記憶體內的資料時,會被所有 threads 存取,與此同時有可能會發生兩個指標指向同一個位置並且擁有同樣的值,以上會造成一種情況就是兩個 thread 同時在更改同一塊記憶體。
在 POSIX Threads (Portable Operating System Interfaces,又稱 PThreads ) 還沒有被定義的年代,每家硬體供應商都有自己對 multi-threads 獨特的寫法,導致程式設計師很難整合多個硬體的 multi-threads 來研發產品,而為了解決此一問題,定義了標準的程式介面。
為了避免兩個執行緒 thread 同時在更改同一會記憶體,所以同步執行緒的動作是必要的,而以下則為幾種同步的方式
mutex 和 semaphore 的差別?
最大的差異在於 Mutex 只能由上鎖的 thread 解鎖,而 Semaphore 沒有這個限制,可以由原本的 thread 或是另外一個 thread 解開。另外,Mutex 只能讓一個 thread 進入 critical section,Semaphore 的話則可以設定要讓幾個 thread 進入。這讓實際上使用 Mutex 跟 Semaphore 場景有很大的差別。
舉例而言,Mutex 的兩個特性:一個是只能有持鎖人解鎖、一個是在釋放鎖之前不能退出的特性,讓 Mutex 叫常使用在 critical section 只能有一個 thread 進入,而且要避免 priority inversion 的時候;Semaphore 也能透過 binary semaphore 做到類似的事情,卻沒有辦法避免 priority inversion 出現。
而 Semaphore 更常是用在同步兩個 thread 或功能上面,因為 Semaphore 實際上使用的是 signal 的 up 與 down,讓 Semaphore 可以變成是一種 notification 的作用,例如 A thread 執行到某個地方時 B thread 才能繼續下去,就可以使用 Semaphore 來達成這樣的作用。
需特別注意在 mutex 的型態等於 PTHREAD_MUTEX_INITIALIZER
,mutex 和 semaphore 的某些行為會看似一樣,但是此行為其實是被定義為 undefined behavior,參考自 pthread_mutex_lock
If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to recursively lock the mutex results in undefined behavior. Attempting to unlock the mutex if it was not locked by the calling thread results in undefined behavior. Attempting to unlock the mutex if it is not locked results in undefined behavior.
資料來源 : 你用的 Mutex 真的是你知道的 Mutex 嗎?
mutex_lock
Dijkstra 透過 Binary Semaphore 來嘗試解決在共享記憶體上的 race condition 的問題。方法為透過隔絕任務開始和任務結束之間的時間來阻止其他可能的變化。而上述情況可能會有以下問題產生:
簡單來說就是在撰寫多執行緒程式時,執行緒是否與其他執行緒分隔
參考資訊
並行程式設計
An Introduction to Lock-Free Programming
Department of Computing Imperial College of Science, Technology and Medicine
What are Pthreads?
RCU 為 Read-Copy-Update 的縮寫,簡單來說就是在多執行緒的環境下,對某個資料結構進行資料的更新並且對每個執行緒共享數據結構。
RCU 考慮以下議題:
寬限期
為什麼要寬限期?
訂閱發布制 (Publish-Subscribe)
參考資訊
Linux 核心設計: 淺談同步機制
Mutex, Semaphore, the difference, and Linux kernel
Linux 核心設計: RCU 同步機制
Read-copy-update
參考資訊