一、進程和線程的對比
線程 | 進程 | |
定義 | 輕量級的進程。是進程中的執行單元,作為CPU調度的基本單位 | 進程時程序的一次執行過程,作為CPU的資源分配的基本單位 |
優勢 |
| 創建多個子進程,進程之間空間相互獨立---進程的穩定性、可靠性、安全性高 |
缺點 |
| 進程間,共享數據不方便 |
二、解決線程資源競爭問題 --- 線程互斥
1.名詞解釋
- 臨界資源----共享資源
- 臨界區----:一段代碼區域(訪問臨界資源的那段代碼)
- 原子操作----要么不操作,如果要操作,一定是一次性完成的操作,不可被打斷;
- 互斥----在多線程中對臨界資源的排他性訪問
- 互斥機制===》互斥鎖===》保證臨界資源團的訪問控制;
????????為了保證臨界資源(共享資源)的完整操作,增加了鎖的機制,即同時滿足互斥訪問(線程1訪問,線程2不可被訪問),+原子性操作(訪問的整個過程必須完整,不可被打斷)。
2.框架:
定義互斥鎖 ===》 齒梳化鎖 ===》 加鎖 ===》 解鎖 ===》 銷毀
????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????? ?????
3.函數
pthread_mutex_t? ?+鎖命名? ? ? ? ? ? ? 【在全局變量中定義】
pthread_mutex_t? ?+鎖命名 +PTHREAD_MUTEX_INITIALIZER? ? ? ? ? ? ? ? 【靜態初始化】
pthread_mutex_init();? ? ? ? ? ? ? ? ? ? ? ? 【在mian函數定義】【動態初始化】
(1)功能:將已經定義好的互斥鎖初始化
(2)參數:
? ? ? ? mutex:要初始化的互斥鎖
? ? ? ? atrr:初始化的值,一般默認 NULL;
(3)返回值:
? ? ? ? ? ? ? ? 成功返回0;
? ? ? ? ? ? ? ? 失敗返回非0;
pthread_mutex_lock();? ? ? ? ? ? ? ? ? ? ? ? ? ? ?【加鎖】
(1)用指定的互斥鎖開始加鎖代碼,加鎖后的代碼到解鎖部分代碼屬于原子操作;在加鎖期間其他進程/線程都不可以操作該部分代碼;如果函數在執行的時候,metex以及被其他部分,使用則代碼阻塞;
(2)參數:mutex 用來給代碼枷鎖的互斥鎖
(3)返回值
? ? ? ? ? ? ? ? 成功返回0;
? ? ? ? ? ? ? ? 失敗返回非零;
pthread_mutex_uhlock();? ? ? ? ? ? ? ? ? ? ? ? ?【解鎖】
(1)功能:將指定的互斥鎖解鎖,解鎖之后代碼不在排他訪問,一般枷鎖解鎖成對出現。
(2)參數:用來解鎖的互斥鎖;
(3)返回值:
? ? ? ? ? ? ? ? 成功返回0;
????????????????失敗返回非零
pthread_mutex_d();? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 【銷毀鎖】
(1)功能:銷毀互斥鎖;
(2)參數:用來銷毀的互斥鎖;
(3)返回值:
? ? ? ? ? ? ? ? 成功返回0;
? ? ? ? ? ? ? ? 失敗返回非零;
代碼示例
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
int cnt =0;
pthread_mutex_t mutex;void *cn1(void *arg)
{ for(int i =0;i<500000;++i){pthread_mutex_lock(&mutex);int tmp = cnt;tmp = tmp+1;cnt = tmp;pthread_mutex_unlock(&mutex);printf("%d\n",cnt);}pthread_exit(NULL);return NULL;
}
void *cn2(void *arg)
{for(int i =0;i<500000;++i){pthread_mutex_lock(&mutex);int tmp = cnt;tmp = tmp+1;cnt = tmp;pthread_mutex_unlock(&mutex);printf("%d\n",cnt);} pthread_exit(NULL);return NULL;
}
int main(int argc, char **argv)
{pthread_t tid1,tid2;pthread_mutex_init(&mutex, NULL);pthread_create(&tid1, NULL, cn1, NULL);pthread_create(&tid2, NULL, cn2,NULL);pthread_join(tid1, NULL);printf("-------------%d\n",cnt);pthread_mutex_destroy(&mutex);pthread_join(tid2, NULL);return 0;
}
總結:
鎖的目的,保證臨界資源的互斥以及原子性訪問
三、線程間協作-----線程同步
- 互斥 ===》 在多線程中臨界資源的排他性訪問
- 同步 ===》 有一定先后順序的,對資源的排他性訪問。-------有順序的訪問
1.信號量背景:交通信號燈
(1)信號量的機制:
- ????????站在a的角度考慮:這塊資源什么時候能用
- ????????站在b的角度考慮:這塊資源什么時候能用
2.信號量分類
- 信號無名量 ===》 線程間通信
- 有名信號量 ===》 進程間通信
3.框架
信號量的定義? ? | sem_t? ?sem; |
信號量的初始化? | ?sem_init() |
信號量的P操作(申請資源)、V操作(釋放資源) | ?sem_wait()/sem_podt(); |
信號量的銷毀 | sem_destroy() |
四、線程同步函數
1、semapthore? ?信號量的定義? ?
? ? ?sem_t? ? ? ? ? ? ? ?sem
? 信號量類型? ? 信號量的變量
2、信號量的初始化
? ? ? ?int sem_init(sem_t *sem, int pshared, unsigned int value);
(1)功能:將已經定義好的信號量賦值。
(2)參數:
- sem:要初始化的信號量
- pthread? ?=0? :表示線程間使用信號量;
? ? ? ? ? ? ? ? ? ? !=0:表示進程間使用的信號量
- value:信號量的初始值,一般無名信號量-------代表一類資源的個數;
(3)返回值:
????????????????成功返回0;
? ? ? ? ? ? ? ? 失敗返回-1;
3.P操作、V操作?
P操作------申請資源
(if(是否有資源可用)
???????????????? ? 有;則程序往下使用資源
? ? ? ? ? ? ? ? ? 無;程序阻塞,等待資源可用
V操作 ------ 釋放資源
????????????????if(是否有仍無需要資源)
? ? ? ? ? ? ? ? ? 有:釋放資源給對應的任務用;
? ? ? ? ? ? ? ? ? 無:讓資源個數加一,表示可用的資源數量多了一個,即新產生了一個資源;
int sem_wait(sem_t *sem); 【 P操作】
(1)功能:判斷當前sem信號量是否有資源可用;如果sem有資源(==1),則申請資源。程序繼續云頂;如果sem沒有資源(==0),則線程阻塞等待,一旦有資源,組自動盛情資源并繼續運行;
注意:sem申請資源后回自動執行,sem = sem -1;
(2)參數:sem要判斷信號量的資源
(3)返回值:
? ? ? ? ? ? ? ? ?成功返回0;
? ? ? ? ? ? ? ? 失敗返回-1;
int sem_post(sem_t *sem); 【V操作】
(1)功能 :?函數可以將指定的sem信號量資源釋放,并默認執行,sem = sem+1;?線程在該函數上不會阻塞。
(2)參數:sem要釋放資源的信號量;
(3)返回值
? ? ? ? ? ? ? ? ?成功返回0;
? ? ? ? ? ? ? ? 失敗返回-1;
4.信號量的銷毀
?int sem_destroy(sem_t *sem);
?(1)功能:使用完畢將指定的信號量銷毀
(2)參數:sem要銷毀的信號量
(3)返回值:
? ? ? ? ? ? ? ? ?成功返回0;
? ? ? ? ? ? ? ? ?失敗返回-1;
信號的操作:-----主要用來實現線程間的順序? ? ? ?
示例代碼
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>#include <semaphore.h>
sem_t sem_r;
sem_t sem_w;
char buf[1024] = {0};
void *sh1(void *arg)
{while(1){sem_wait(&sem_w);fgets(buf, sizeof(buf),stdin);sem_post(&sem_r);}
}
void *sh2(void *arg)
{while(1){sem_wait(&sem_r);printf("buf = %s",buf);sem_post(&sem_w);}
}
int main(int argc, char **argv)
{pthread_t tid1,tid2;sem_init(&sem_w, 0, 1);sem_init(&sem_r, 0, 0);pthread_create(&tid1, NULL, sh1, NULL);pthread_create(&tid2, NULL, sh2, NULL);pthread_join(tid1, NULL);pthread_join(tid1, NULL);return 0;
}
五.應用
1.什么時候用
- 鎖 ----有多線程,公共資源,互斥訪問
- 信號量-----多線程,公共資源,順序訪問