Linux C系統編程-線程取消例程和同步互斥 (三)
線程取消例程函數
當線程收到取消請求時,先不要馬上響應取消請求,首先執行一個線程的例程函數,執行完這個函數再響應取消。
一般地,線程取消例程函數里面都是寫一些釋放公共資源的內容、在Linux系統,公共資源中的互斥鎖,條件變量。
使用線程取消例程函數,是為了防止線程帶著系統公共資源一起被取消,如果帶著系統資源而退出,則其他的線程就無法再次使用該資源。
只需要在線程中調用
pthread_cleanup_push()
功能: push thread cancellation clean-up handlers -> 線程取消例程函數
routine:取消例程函數
arg:傳遞例程函數的參數
信號處理函數: void fun(int sig)
線程創建: void *fun(void *arg)
線程取消例程函數: void fun(void *)
將取消例程函數彈棧
void pthread_cleanup_pop(int execute);
execute: 0 -> 不執行例程
非0 -> 執行例程
子線程收到主線程的退出時,不要馬上取消,而是先打印"I recv cancel!\n",再取消。
void fun(void *arg)
{
printf("I recv cancel!\n");
}
void *routine(void *arg)
{
pthread_cleanup_push(fun,NULL);
int i;
for(i=0;i<10;i++)
{
sleep(1);
printf("%d\n",i);
}
pthread_exit(NULL); // 還沒來得及刪除函數就pthread_exit退出了,那么還是會執行例程函數
return; // 還沒來得及刪除函數就return退出了,那么不會執行例程函數
sleep(1);
pthread_cleanup_pop(1); //正常刪除例程函數,如果參數非0 -> 執行
// 正常刪除例程函數,如果是0, -> 不執行
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,routine,NULL);
pthread_join(tid,NULL);
return 0;
}
線程同步互斥
使得多個線程之間處理任務時有先后順序:
有名信號量 對象:進程
無名信號量 對象:線程
有名信號量
創建并打開一個有名信號量
sem_open()
功能: initialize and open a named semaphore -> 初始化并且打開一個有名信號量
使用格式:
name: 有名信號量的名字,要求是必須以“/”開頭 例如: /sem_test
oflag: O_CREAT 不存在則創建 需要額外填寫兩個參數
O_EXCL 存在則報錯
mode: 八進制權限 0777
value: 有名信號量起始值
返回值:
成功: 有名信號量起始地址
失敗: SEM_FAILED -1
有名信號量P/V操作
P操作: sem_post() 資源數+1 紅燈(0) 綠燈(1)
V操作: sem_wait() 資源數-1 綠燈(1) 紅燈(0)
sem: 有名信號量的地址
關閉有名信號量
sem_close()
功能: sem_close - close a named semaphore
銷毀有名信號量
sem_unlink()
功能: sem_unlink - remove a named semaphore
name: 有名信號量的名字
Jack進程與Rose進程之間使用共享內存來通信,使用有名信號量來處理同步互斥
Jack:
int main()
{
//1. 申請key值
key_t key = ftok(".",10);
//2. 根據key值申請ID號
int shmid = shmget(key,1024,IPC_CREAT|0666);
//3. 根據ID號申請空間
char *p = (char *)shmat(shmid,NULL,0);
//4. 創建并且打開一個有名信號量
sem_t *sem = NULL;
sem = sem_open("/sem_test",O_CREAT,0777,0); //說明當前的資源數為0
//5. 不斷往共享內存中寫入數據
while(1)
{
fgets(p,1024,stdin); //把車開進車庫
sem_post(sem); //資源數為1
//0->1
if(strncmp(p,"quit",4) == 0)
{
break;
}
}
}
Rose:
int main()
{
//1. 申請key值
key_t key = ftok(".",10);
//2. 根據key值申請ID號
int shmid = shmget(key,1024,IPC_CREAT|0666);
//3. 根據ID號申請空間
char *p = (char *)shmat(shmid,NULL,0);
//4. 創建并且打開一個有名信號量
sem_t *sem = NULL;
sem = sem_open("/sem_test",O_CREAT,0777,0); //說明當前的資源數為0
//5. 不斷往共享內存中寫入數據
while(1)
{
sem_wait(sem); //一直阻塞詢問資源能否-1 如果當前資源為1,則函數返回
//如果當前資源為0,則函數阻塞
//1->0
printf("from Jack:%s",p);
if(strncmp(p,"quit",4) == 0)
{
break;
}
}
}
無名信號量
對象: 線程
由于無名信號量是無名的,所以說不能打開,但是可以初始化。
sem_init()
功能:初始化無名信號量 initialize an unnamed semaphore
sem: 信號量的地址
pshared: 作用的對象 0 線程
非0 進程
value:信號量的初始化值
有名信號量P/V操作
P操作: sem_post() 資源數+1 紅燈(0) 綠燈(1)
V操作: sem_wait() 資源數-1 綠燈(1) 紅燈(0)
#include <semaphore.h>
int sem_post(sem_t *sem); unlock semaphore
int sem_wait(sem_t *sem); - lock semaphore
sem: 有名信號量的地址
銷毀無名信號量
sem_destroy()
功能: sem_destroy - destroy an unnamed semaphore
int sem_destroy(sem_t *sem);
sem:需要銷毀的無名信號量的地址
創建5個線程,每一個線程的任務都是一樣
任務: 將"helloworld"字符串1秒打印一個字符 完成任務需要10秒。
要求5個子線程依次打印helloworld,不要同時打印。
void *routine(void *arg)
{
sem_t *sem = (sem_t *)arg;
//叉子:1
//誰先能把資源數-1,誰就吃蛋糕!
sem_wait(sem);
//叉子:0 -> 這時別的線程就沒辦法搶占了這個資源
int i;
char buf[] = "helloworld";
for(i=0;buf[i]!='\0';i++)
{
fprintf(stderr,"%c",buf[i]);
sleep(1);
}
//吃完蛋糕了,應該將叉子放出來,資源數變成1
sem_post(sem);
//叉子:1 -> 別的線程就有機會搶占資源。
pthread_exit(NULL);
}
int main()
{
//1. 初始化無名信號量
sem_t sem;
sem_init(&sem,0,1); //當前資源數為0
//2. 產生5個子線程
pthread_t tid[5]; //0~4
int i;
for(i=0;i<5;i++)
{
pthread_create(&tid[i],NULL,routine,(void *)&sem);
}
//3. 回收資源
for(i=0;i<5;i++)
{
pthread_join(tid[i],NULL);
}
sem_destroy(&sem);
return 0;
}
智能推薦
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
猜你喜歡
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...
19.vue中封裝echarts組件
19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...