星期六, 8月 26, 2017

Thread Safety

thread-safe 函數給多個 thread 同時重複呼叫時不會造成錯誤,包括原本就已經是 reentrant 的函數,以及用 mutex 或其它方式改良過的函式。

thread 排程不是 preemptive 會嗎?

threadFunc() 為例,對全域變數 glob 作 loops 次「加一」。當有兩個 thread t1 和 t2 都呼叫此函數,「加一」動作並不是 atomic operation,實際上包括了「讀 glob」、「glob 加 1」、和「寫 glob」,有時中間會插入另一個 thread,而造成結果被覆蓋而錯誤。
t1 讀 glob 為 1
t2 讀 glob 為 1
t2 加 1 後寫 glob 為 2
t1 加 1 後寫 glob 為 2
結果是 2,但正確結果是 3。

註:glob 是 int,所以 read 跟 write 可以一次完成。如果資料量大於 int 或沒對齊 int boundary,read 跟 write 無法一次完成,也可能插入其它 thread 的動作。

改正方式:
  1. 使用 mutex (如有 mutex 的 threadFunc())。例如一個變數配置一個 mutex,用在存取需要 critical sections 的部份。
  2. 一次只讓一個 thread 執行 (serialized)。如果 thread 花很多時間執行此函數,會失去 concurrency。
POSIX 裡的函數,有列出除了哪些以外,都必須是 thread-safe (可見 man pthreads)

reentrant 函數能夠不用 mutex 達到 thread safety。reentrant 函數
  • 不使用全域變數 (要回給 caller 或呼叫間需要保留的任何資訊,必須存在 caller 配置的 buffers。)
  • 不改變自身程式碼
  • 不呼叫 no-reentrant 函數

有些標準函數不是 reentrant 的,但有另外提供名稱後置 _r 的 reentrant 版本,這些函數需要 buffer 回傳結果。

例如 asctime_r()、ctime_r()、getgrgid_r()、getgrnam_r()、getlogin_r()、getpwnam_r()、getpwuid_r()、gmtime_r()、localtime_r()、rand_r()、readdir_r()、strerror_r()、strtok_r()、及 ttyname_r()。

glibc 提供的 crypt_r()、gethostbyname_r()、getservbyname_r()、getutent_r()、getutid_r()、getutline_r()、及 ptsname_r()。

參考:
  1. :《The Linux Programming Interface》chap. 31.1
  2. 可重入與執行緒安全 (reentrant vs thread-safe) Part 1/Part 2/Part 3
  3. coroutine
  4. https://en.wikipedia.org/wiki/Non-blocking_algorithm
  5. https://en.wikipedia.org/wiki/Real-time
  6. Emulated atomic operations and real-time scheduling,處理器原生只支援最基本的 atomic operations,如何 emulate 其它 atomic operation?在Linux kernel 只需要暫時關閉中斷 (SMP 不行)。

必須避免執行緒同時修改資料結構,破壞了資料的正確性

如果要鎖住資料結構,通常需要 read-modify-write

  1. 檢查目前是否有人正在修改 (有 read 動作)
  2. 如果沒人在修改,就先「鎖上」後修改 (modify-write)
硬體必須提供特別的指令,可以同時 1. 檢查 2. 檢查通過立刻上鎖

POSIX 提供高階的鎖定機制,如:semaphore、mutex、spinlock、rwlock

星期五, 8月 25, 2017

Create Wi-Fi Hotspot in Lubuntu

ASUS 筆電 PU301LA 安裝 Lubuntu 更新到 16.04 LTS (xenial)
執行「iw list」查看 Supported interface modes: 有 AP
已安裝 dnsmasq

點選右下角網路圖示 → 點選「Edit Connections...」 → 按「Add」鍵 → Choose a Connection Type 的選單選「Wi-Fi」 → 按「Create...」鍵 → Connection name 是設定檔名稱,可沿用自動產生的或另取,例如「hotspot」

Wi-Fi 標籤
  • SSID:設成想要的 Wi-Fi 網路名稱
  • Mode:選 Hotspot
  • Device:選使用的無線網卡
Wi-Fi Security 標籤
  • Security 選 WPA & WPA2 Personal
  • Password 設定
點選右下角網路圖示 → 點選「Create New Wi-Fi Network...」 → Connection: 選擇剛剛建立的 Connection name → 按「Create」鍵

註:設定檔 /etc/NetworkManager/system-connections/`Connection name`
註:不需要安裝 hostapd
註:似乎無法隱藏 SSID [參考 https://askubuntu.com/questions/554307/is-there-any-way-to-create-a-hidden-hotspot-from-ubuntu]

2017/08/29 後記:系統更新為 Lubuntu 17.04,「Create Net Wi-Fi Network...」沒有出現 「Connection:」供選擇的解法
sudo vi /etc/NetworkManager/NetworkManager.conf
在最後加上
[device]
wifi.scan-rand-mac-address=no
sudo service network-manager restart

參考:
  1. 3 Ways to Create Wifi Hotspot in Ubuntu 14.04 (採用內容主要描述的第三種方法)
  2. 把電腦的無線網卡當無線 AP 讓行動裝置連線上網 (iw list 等硬體查看參考)
  3. Create Wi-Fi hotspot in Lubuntu 15.04 (不是採用內容所敘述的方法,作為將來參考用)
  4. https://blogs.gnome.org/thaller/2016/08/26/mac-address-spoofing-in-networkmanager-1-4-0/

pthread cancel

pthread_cancel() 送取消請求給 thread,thread 依據其取消狀態 (cancellation state) 及取消 type 因應。

thread 的取消狀態有啟用 (預設) 和停用,可由 pthread_setcancelstate() 設定。停用時收到取消請求暫不處理 (queued),直到啟用。收到取消請求且啟用時,type 決定取消何時進行。

thread 的取消 type 有 deferred (預設) 及 asynchronous,可由 pthread_setcanceltype() 設定。Asynchronous 表示可在任何時間點取消,但系統不保證立即進行。Deferred 表示直到 thread 呼叫到含有取消點 (cancellation point) 的函數才進行取消動作。

取消動作依序包括:
  1. pop 每個 Cancellation clean-up handlers 並執行。(見 pthread_cleanup_push())
  2. 呼叫 thread-specific data destructors (見 pthread_key_create())
  3. thread 結束 (見 pthread_exit())
pthread_cancel() 回傳值 0 表示成功送出請求。用 pthread_join() 得到 thread 的 exit status 是 PTHREAD_CANCELED 才能知道取消動作完成。

Linux 用 signal 實作 thread 取消,在 NPTL 是第一個 real-time signal (也就是 signal 32)。

pthread_cancel() MT-safe

async-cancel-safe 函數:能夠在啟用 asynchronous 取消的應用安全使用的函數,包括 pthread_cancel()、pthread_setcancelstate()、pthread_setcanceltype()。

必須含有取消點的函數:包括 sleeps() 等,列表見 man pthreads
  • pthread_testcanel():測試是否取消
可能含有取消點的函數:列表見 man pthreads

應用:有些 thread 設計是無窮的迴圈,其它 thread 呼叫 pthread_cancel() 作為結束。

參考來源
  1. man pthread_canel
  2. man pthreads