線程同步與程序通信
線程同步
互斥量
- 臨界資源:在一段時間内隻允許一個任務(線程或程序)通路資源。任務之間采用互斥的方式通路臨界資源
- 互斥量:
初始化、加鎖、解鎖、銷毀pthread_mutex_t mutex;
- 加鎖:
在通路臨界資源前,對互斥量進行加鎖。int pthread_mutex_lock(); int pthread_mutex_trylock();
未加鎖則加鎖,加鎖後不重複加鎖。trylock()
- 解鎖:
通路完成後對互斥量解鎖int pthread_mutex_unlock();
- 銷毀:
互斥量使用完畢後對互斥量進行銷毀,釋放資源。int pthread_mutex_destory();
- 加鎖:
條件變量
- 任務同步:多個線程都要通路臨界資源又要互相合作,一個任務的執行依賴與另一個任務的執行情況。
- 條件變量:
和互斥量一起使用,允許線程以互斥的方式阻塞等待條件的發生即為同步關系pthread_cond_t cond;
- 觸發條件變量的線程:互斥量加鎖>>某一操作>>觸發條件變量>>互斥量解鎖
- 等待條件變量的線程:互斥量加鎖>>等待條件變量>>某一操作>>互斥量解鎖
- 銷毀:
條件變量不再使用後進行銷毀,釋放空間pthread_cond_destory();
- 等待條件變量:
使得調用程序進入阻塞狀态,直到條件觸發pthread_cond_wait();
- 觸發條件變量:
可觸發并喚醒等待條件變量的線程pthread_cond_signal();/pthread_cond_broadcast();
- 條件變量與互斥量要配合使用
- 條件變量的使用場景伴随着臨界資源的使用
- 在調用
前需要使互斥量處于加鎖狀态,通過原子操作将調用線程放到該條件變量等待線程隊列(臨界資源)中pthread_cond_wait();
//等待條件變量的操作 pthread_mutex_lock(); pthread_cond_wait(); pthread_mutex_unlock();
- 條件變量的使用
讀寫鎖
- 讀寫關系:讀寫互斥、寫寫互斥、讀讀不互斥
- 讀寫鎖:
pthread_rwlock_t;
- 加讀鎖:
阻塞加鎖pthread_rwlock_rdlock();/非阻塞加鎖pthread_rwlock_tryrdlock();/限時加讀鎖pthread_rwlock_timedrdlock();
- 加寫鎖:
阻塞加鎖pthread_rwlock_wrlock();/非阻塞加鎖pthread_rwlock_trywrlock();/限時加讀鎖pthread_rwlock_timedwrlock();
- 解鎖:統一解鎖函數,最近配對原則解鎖
pthread_rwlock_unlock();
- 加讀鎖:
程序通信
- 管道和命名管道:檔案的形式實作不同程序共享資源
- XSI IPC機制:LINUX系統使用的程序通信機制
功能 信号量 共享記憶體 消息隊列 建立或打開一個IPC對象,獲得對IPC機制的通路權 semget shmget msgget IPC操作:信号量操作;連接配接/釋放共享記憶體;發送/接收消息 semop shmat/shmdt msgsnd/msgrcv IPC控制:獲得/修改IPC對象狀态,“删除”IPC對象 semctl shmctl msgctl
消息隊列
- 消息隊列:消息的連結清單,有寫或者讀權限的程序可以按照一定的規則添加或者讀取消息
- 消息隊列的操作
sys/types.h sys/ipc.h sys/msg.h
- 打開或建立消息隊列對象:
int msgget();
- 從消息隊列接收消息:
int msgrcv();
- 向消息隊列發送消息:
int msgsnd();
- 消息隊列控制操作:
int msgctl();
- 打開或建立消息隊列對象:
信号量
- 互斥信号量:任務之間互斥通路臨界資源 初始值為1
- 計數信号量:任務之間競争通路共享資源 初始值大于1,表示共享資源個數
- 二值信号量:任務之間的同步機制 初始值為0
- 信号量的資料結構
struct s { int count; //資源計數 Queue queue; //任務阻塞隊列 }; int init(); // 初始化 int P(); // P操作 int V(); // V操作
- P操作:配置設定資源
--s.count; if(s.count < 0) { 調用程序進入s.queue; 阻塞調用程序; }
- V操作:釋放資源
++s.count; if(s.count <= 0 ) { 從阻塞隊列s.queue中取出一個程序P; 程序P進入就緒隊列; }
- 信号量集的操作
sys/types.h sys/ipc.h sys/sem.h
- 建立或者打開信号量集對象
int semget();
#include<stdio.h> #include<sys/sem.h> #define MYKEY 0x1a0a //定一個ipc的key值 int main() { int semid; semid = semget(MYKEY,1,IPC_CREAT|IPC_R|IPC_W|IPC_M); //建立一個信号量集對象 printf("semid = %d\n",semid); return 0; }
- 信号量PV操作
:根據參數int semop();
判斷執行的操作類型short sem_op;
-
:信号量V操作,增加信号量的值sem_op > 0
-
:信号量P操作,減少信号量的值sem_op < 0
-
:對信号量的目前值是否為0的測試sem_op = 0
//實作P操作 static int semaphore_v(void) { struct sembuf sem_b; sem_b.sem_num = 0; //信号量編号 sem_b.sem_op = -1; // P操作 sem_b.sem_fg = SEM_UNDO; //在程序沒釋放信号量而退出時,系統自動釋放該程序中未釋放的信号量 if(semop(sem_id, &sem_b,1) == -1) { fprintf(stderr,"semaphore_p failed\n"); return 0; } return 1; } //實作V操作 static int semaphore_v(void) { struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; // V操作 sem_b.sem_fg = SEM_UNDO; if(semop(sem_id, &sem_b,1) == -1) { fprintf(stderr,"semaphore_v failed\n"); return 0; } return 1; }
-
- 信号量控制
:int semctl();
控制指令參數int cmd;
- 對信号量集的控制指令:
删除;IPC_RMID
設定參數;IPC_SET
擷取參數;IPC_STAT
擷取系統資訊IPC_INFO
- 對信号量的控制指令:
設定信号量的值;SETVAL
擷取信号量的值;GETVAL
擷取信号量擁有者的PID值GETPID
//信号量初始化 int init_sem(int sem_id, int init_value) { union semun_sem_union; sem_union.val = init_value; if(semctl(sem_id,0,SETVAL,sem_union) == -1) { perror("Initialize semaphore"); return -1; } return 0; } //從系統中删除信号量 int del_sem(int sem_id) { union semun sem_union; if(semctl(sem_id,0,IPC_RMID,sem_union) == -1) { perror("Initialize semaphore"); return -1; } }
- 對信号量集的控制指令:
- 建立或者打開信号量集對象
共享記憶體
- 共享記憶體:不同程序可以将同一段記憶體空間連結到自己的位址空間中,類似實體空間中的全局變量
- 共享記憶體的操作
sys/types.h sys/ipc.h sys/shm.h
- 建立或者打開共享記憶體對象
int shmget();
- 将共享記憶體連結到調用的程序的位址空間
void *shmat();
- 删除程序的共享記憶體連結
int shmdt();
- 對共享記憶體的操作
int shmctl();
- 建立或者打開共享記憶體對象
- 共享記憶體應用–生産者/消費者問題
//緩存池結構 struct BufferPool { char Buffer[5][100]; int index[5]; };