三種專門用於線程同步的機制:POSIX信號量,互斥量和條件變數.
在Linux上信號量API有兩組,一組是System V IPC信號量,即PV操作,另外就是POSIX信號量,POSIX信號量的名字都是以sem_開頭.
phshared參數指定信號量的類型,若其值為0,就表示這個信號量是當前進程的局部信號量,否則該信號量可以在多個進程之間共享.value值指定信號量的初始值,一般與下面的sem_wait函數相對應.
其中比較重要的函數sem_wait函數會以原子操作的方式將信號量的值減一,如果信號量的值為零,則sem_wait將會阻塞,信號量的值可以在sem_init函數中的value初始化;sem_trywait函數是sem_wait的非阻塞版本;sem_post函數將以原子的操作對信號量加一,當信號量的值大於0時,其他正在調用sem_wait等待信號量的線程將被喚醒.
這些函數成功時返回0,失敗則返回-1並設置errno.
生產者消費者模型:
生產者對應一個信號量:sem_t procer;
消費者對應一個信號量:sem_t customer;
sem_init(&procer,2)----生產者擁有資源,可以工作;
sem_init(&customer,0)----消費者沒有資源,阻塞;
在訪問公共資源前對互斥量設置(加鎖),確保同一時間只有一個線程訪問數據,在訪問完成後再釋放(解鎖)互斥量.
互斥鎖的運行方式:串列訪問共享資源;
信號量的運行方式:並行訪問共享資源;
互斥量用pthread_mutex_t數據類型表示,在使用互斥量之前,必須使用pthread_mutex_init函數對它進行初始化,注意,使用完畢後需調用pthread_mutex_destroy.
pthread_mutex_init用於初始化互斥鎖,mutexattr用於指定互斥鎖的屬性,若為NULL,則表示默認屬性。除了用這個函數初始化互斥所外,還可以用如下方式初始化:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER。
pthread_mutex_destroy用於銷毀互斥鎖,以釋放佔用的內核資源,銷毀一個已經加鎖的互斥鎖將導致不可預期的後果。
pthread_mutex_lock以原子操作給一個互斥鎖加鎖。如果目標互斥鎖已經被加鎖,則pthread_mutex_lock則被阻塞,直到該互斥鎖佔有者把它給解鎖.
pthread_mutex_trylock和pthread_mutex_lock類似,不過它始終立即返回,而不論被操作的互斥鎖是否加鎖,是pthread_mutex_lock的非阻塞版本.當目標互斥鎖未被加鎖時,pthread_mutex_trylock進行加鎖操作;否則將返回EBUSY錯誤碼。注意:這里討論的pthread_mutex_lock和pthread_mutex_trylock是針對普通鎖而言的,對於其他類型的鎖,這兩個加鎖函數會有不同的行為.
pthread_mutex_unlock以原子操作方式給一個互斥鎖進行解鎖操作。如果此時有其他線程正在等待這個互斥鎖,則這些線程中的一個將獲得它.
三個列印機輪流列印:
輸出結果:
如果說互斥鎖是用於同步線程對共享數據的訪問的話,那麼條件變數就是用於在線程之間同步共享數據的值.條件變數提供了一種線程之間通信的機制:當某個共享數據達到某個值時,喚醒等待這個共享數據的線程.
條件變數會在條件不滿足的情況下阻塞線程.且條件變數和互斥量一起使用,允許線程以無競爭的方式等待特定的條件發生.
其中pthread_cond_broadcast函數以廣播的形式喚醒所有等待目標條件變數的線程,pthread_cond_signal函數用於喚醒一個等待目標條件變數線程.但有時候我們可能需要喚醒一個固定的線程,可以通過間接的方法實現:定義一個能夠唯一標識目標線程的全局變數,在喚醒等待條件變數的線程前先設置該變數為目標線程,然後採用廣播的方式喚醒所有等待的線程,這些線程被喚醒之後都檢查該變數以判斷是否是自己.
採用條件變數+互斥鎖實現生產者消費者模型:
運行結果:
阻塞隊列+生產者消費者
運行結果:
『貳』 linux 線程中,線程宿主函數是什麼意思宿體函數又是什麼意思二者有什麼區別最好能舉個例子。
宿主函數是你調用建立線程的函數,而宿體函數是你線程運行起來後執行的函數
『叄』 Linux的C編程線程問題
這么多內容,沒時間御沒寫大賀,給你點資料,自己去看了寫滾拆派吧:
http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part1/index.html
http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part2/index.html
http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part3/index.html
http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part4/index.html
http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part5/index.html
『肆』 嵌入式與Linux(五):Linux線程
姓名:王央京 學號:18050100052 學院:電子工程學院
轉自:https://blog.csdn.net/qq_22847457/article/details/89371217
【嵌牛導讀】本文介紹了Linux線程的相關信息
【嵌牛鼻子】Linux線程
【嵌牛提問】在了解Linux系統後,能否具體介紹線程的概念?
【嵌牛正文】
類Unix系統中,早期是沒有「線程」概念的,80年代才引答握態入,藉助進程機制實現出了線程的概念。因此在這類系統中,進程和線程關系密切。一個進程可以有多個線程,這個進程本身也叫做線程只不過是主線程。通常主線程分配任務給子線程做。程序設計時候就可以某一時刻不止做一件事情,每一個線程處理各自獨立的任務。
多個線程可以訪問相同的存儲地址空間和文件描述符。同一進程內的線程共享以下數據:全局內存、進程指令、打開的文件、信號處理函數和信號處置、當前工作目錄、用戶ID和用戶組ID、大多數數據。每個線程有各自的線程ID、寄存器集合(包括程序計數器和棧指針)、棧、errono、信號掩碼、優先順序。
線程的優點有提高程序並發性、開銷小和數據通信、共享數據方便等。線程的缺點有庫函數不穩定、調試編寫困難、gdb不支持、對信號支持不好等。除此之外,多線程內如果其中一個線程出現了 除0、野指針 等問題會造成該線程崩潰,進而導致整個進程終止。同時,線程是進程的執行分支,線程出異常,就類似進程出異常,進而觸發信號機制,終止進程,進程終止,該進程內的所有線程也就隨即退出。
從上述分析來看,線程的優點相對突出,缺點均不是硬傷。Linux下由於實現方法導致進程、線程差別不是很大。
線程有一套完整的與其有關的函數庫調用,它們中的絕大多數函數名都以pthread_開頭。為了使用這些函數庫調用,我們必須定義宏_REENTRANT,在程序中包含頭文件pthread.h,並且在編譯程序皮嘩時需要用選項-lpthread來鏈接線程庫。其中常用的函數庫如下:
1. pthread_self函數獲取線程ID,其作用對應進程中getpid()函數。
2. pthread_create函數創建一個新線程,其作用對應進程中fork()函數。
3. pthread_exit函數將單個線程退出,其作用對應進程中exit()函數
4. pthread_join函數阻塞等待線程退出,獲取線程退出狀態其作用,對清源應進程中waitpid()函數。
5. pthread_cancel函數殺死(取消)線程其作用,對應進程中kill()函數。
6. pthread_detach函數實現線程分離。
『伍』 Linux多線程程序中有哪些變數類型,被映射到哪個地址空間,有幾個運行實例
在 Linux 多線程編程中,通常會使用以下幾種變數類型:
全局變數:定義在所有函數之外的變數,作用域在整個程序中都可見。全局變數被映射到進程的數據段中,所有線程都可以訪問它們。在多線程程序中,需要注意全局變數的並發訪問問題,避免出現競爭條件。
局部變數:定義在函數內部的變數,作用域僅限於函數內部。每個線程都有自己的棧空間,虧祥局部變數被分配在棧上,每個線程都有自己獨立的棧空間,互不幹擾。
線程私有變數:每個線程都有自己的私有變數。可以使用 pthread_key_create() 函數創建一個線程私有變數,使用 pthread_getspecific() 和 pthread_setspecific() 函數來設置和獲取線程私有變數的值。線程私有變數被映射到進程的線程局部存儲段(Thread Local Storage, TLS)中,每個線程都有自己獨立的 TLS,互不幹擾。
共享變數:被多個線程共享的變數。在多線程程序中,需要使用鎖(如互斥鎖、讀寫鎖)等機制來保護共享變數,避免出現競爭條件橡鉛。共享變數被映射到進程的數據段中,所有線程都可以訪問它們。
需要注意的是,在多線程程序中,這些變數類型在地址空間中的位置和數量都是相對復雜的,因為每個線程都有自己獨梁空好立的棧空間和 TLS,這些變數的地址在不同的線程中可能是不同的。因此,在多線程程序中,需要使用適當的同步機制來保護這些變數,以確保程序的正確性和可靠性。
『陸』 linux內核創建內核線程有哪些方法
1.頭文件
#include <linux/sched.h> //wake_up_process()
#include <linux/kthread.h> //kthread_create()、kthread_run()
#include <err.h> //IS_ERR()、PTR_ERR()
2.實現
2.1創建線程
在模塊初始化時,可以進行線程的創建。使用下面的函數和宏定義:
struct task_struct *kthread_create(int (*threadfn)(void *data),
void *data,
const char namefmt[], ...);
#define kthread_run(threadfn, data, namefmt, ...) \
({ \
struct task_struct *__k \
= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
if (!IS_ERR(__k)) \
wake_up_process(__k); \
__k; \
})
例如:
static struct task_struct *test_task;
static int test_init_mole(void)
{
int err;
test_task = kthread_create(test_thread, NULL, "test_task");
if(IS_ERR(test_task)){
printk("Unable to start kernel thread. ");
err = PTR_ERR(test_task);
test_task = NULL;
return err;
}
wake_up_process(test_task);
return 0;
}
mole_init(test_init_mole);
2.2線程函數
在線程函數里,完成所需的業務邏輯工作。主要框架如下所示:
int threadfunc(void *data){
…
while(1){
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop()) break;
if(){//條件為真
//進行業務處理
}
else{//條件為假
//讓出CPU運行其他線程,並在指定的時間內重新被調度
schele_timeout(HZ);
}
}
…
return 0;
}
2.3結束線程
在模塊卸載時,可以結束線程的運行。使用下面的函數:
int kthread_stop(struct task_struct *k);
例如:
static void test_cleanup_mole(void)
{
if(test_task){
kthread_stop(test_task);
test_task = NULL;
}
}
mole_exit(test_cleanup_mole);
3.注意事項
(1) 在調用kthread_stop函數時,線程函數不能已經運行結束。否則,kthread_stop函數會一直進行等待。
(2) 線程函數必須能讓出CPU,以便能運行其他線程。同時線程函數也必須能重新被調度運行。在例子程序中,這是通過schele_timeout()函數完成的。
4.性能測試
可以使用top命令來查看線程(包括內核線程)的CPU利用率。命令如下:
top –p 線程號
可以使用下面命令來查找線程號:
ps aux|grep 線程名
可以用下面的命令顯示所有內核線程:
ps afx
註:線程名由kthread_create函數的第三個參數指定
在分析usb_hub_init()的代碼的時候,忽略掉了一部份.
代碼片段如下所示:
int usb_hub_init(void)
{
……
khubd_task = kthread_run(hub_thread, NULL, "khubd");
……
}
Kthread_run() 是kernel中用來啟動一個新kernel線程的介面,它所要執行的函數就是後面跟的第一個參數.在這里,也就是hub_thread().另外,順帶 提一句,要終止kthread_run()創建的線程,可以調用kthread_stop().
『柒』 linux下C語中用到的線程編程函數
[desktop:~]$ man pthread_mutex
pthread_mutexattr_destroy pthread_mutexattr_settype
pthread_mutexattr_getprioceiling pthread_mutex_destroy
pthread_mutexattr_getprotocol pthread_mutex_getprioceiling
pthread_mutexattr_getpshared pthread_mutex_init
pthread_mutexattr_gettype pthread_mutex_lock
pthread_mutexattr_init pthread_mutex_setprioceiling
pthread_mutexattr_setprioceiling pthread_mutex_timedlock
pthread_mutexattr_setprotocol pthread_mutex_trylock
pthread_mutexattr_setpshared pthread_mutex_unlock
用manpages一下都能查出來。
『捌』 linux線程pthread_cleanuo_push 函數問題
pthread_cleanup_push來注冊清理函數rtn,這個函數有一個參數arg。在以下三種情形之一發生時,注冊的清理函數被執行:
1)調用pthread_exit。
2)作為對取消線程請求(pthread_cancel)的響應。
3)以非0參數調用pthread_cleanup_pop。
注意:
1)如果線程只是由於簡單的返回而終止的,則清除函數不會被調用。
2)如果pthread_cleanup_pop被傳遞0參數,則清除函數不會被調用,但是會清除處於棧頂的清理函數。
『玖』 用Linux,pthread相關函數創建一個調度策略為NORMAL,priority=15的線程,
NORMAL的調度策略是什麼?
創建一個線程很簡單,用pthread_create就可以做到,鄭橘具體使用方法你man下或者搜索都有。
需要提到的是你要改變調度策略和優先氏叢嫌級,我查了下殲手,用sched_setscheler就可以做到了:
int sched_setscheler(pid_t pid, int policy, const struct sched_param *param);
policy是設置調度策略,param是設置優先順序。
『拾』 Linux的線程清理函數
第一個問題,出現兩個pthread_cleanup_push嗎,因為每次只態宴能增加一個退出時處州閉明理的函數,第二個參數為NULL,表示調用處理函數時,函數沒有參數
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
你給他們的參數為0,所以清除函數不會被冊告調用。