1.耦合:耦合是指兩個或兩個以上的體系或兩種運動形式間通過相互作用而彼此影響以至聯(lián)合起來的現(xiàn)象。在軟件工程中,對象之間的耦合度就是對象之間的依賴性。對象之間的耦合越高,維護成本越高,因此對象的設計應使類和構件之間的耦合最小。
2.耦合性:耦合性是程序結(jié)構中各個模塊之間相互關聯(lián)的度量。它取決于各個模塊之間的接口的復雜程度、調(diào)用模塊的方式以及哪些信息通過接口。
3.解耦:字面意思就是解除耦合關系。在軟件工程中,降低耦合度即可以理解為解耦,模塊間有依賴關系必然存在耦合,理論上的絕對零耦合是做不到的,但可以通過一些現(xiàn)有的方法將耦合度降至最低。設計的核心思想就是盡可能減少代碼耦合,如果發(fā)現(xiàn)代碼耦合,就要采取解耦技術。原則就是A功能的代碼不要寫在B的功能代碼中,如果兩者之間需要交互,可以通過接口,通過消息,甚至可以引入框架,但總之就是不要直接交叉寫。
生產(chǎn)者是寫入數(shù)據(jù),消費者是讀取數(shù)據(jù),消費者讀取一個數(shù)據(jù)之后,這個數(shù)據(jù)就沒有了,相當于一個有限緩沖區(qū)的問題。如下圖:
1.緩沖區(qū)的作用相當于解耦
如果兩個進程之間直接交換數(shù)據(jù)的話,一個生產(chǎn)者進程對消費者進程給出數(shù)據(jù),但是消費者進程還沒有機會去讀取,這時生產(chǎn)者進程就會發(fā)生阻塞,等待消費者進程來讀取數(shù)據(jù),兩個進程之間相互影響,具有一定的耦合性。通過上面這樣一個緩沖區(qū)來交換數(shù)據(jù)的話就可以做到解耦。
有了這樣一個緩沖區(qū),如果再增加一個消費者進程來讀取數(shù)據(jù),生產(chǎn)者進程的代碼也不用修改,對生產(chǎn)者進程也沒有什么很大的影響,只是生產(chǎn)者進程產(chǎn)生數(shù)據(jù)的速度會變快。也不會因為增加了一個消費者進程來讀取數(shù)據(jù),而這時生產(chǎn)者進程還沒有產(chǎn)生數(shù)據(jù),使消費者進程發(fā)生阻塞,因為生產(chǎn)者進程產(chǎn)生的數(shù)據(jù)已經(jīng)放到了緩沖區(qū)中,消費者進程可以隨時來讀取。
當然如果緩沖區(qū)被生產(chǎn)者進程產(chǎn)生的數(shù)據(jù)寫滿了,這時生產(chǎn)者進程就會被阻塞住,反之,如果緩沖區(qū)為空,消費者進程想要讀取數(shù)據(jù),那么消費者進程就會被阻塞。所以,一定要注意緩沖區(qū)滿和緩沖區(qū)空的情況,緩沖區(qū)滿的時候生產(chǎn)者不可以寫入數(shù)據(jù),緩沖區(qū)空的時候消費者不可以讀取數(shù)據(jù)。
2.生產(chǎn)者向緩沖區(qū)寫入數(shù)據(jù)和消費者從緩沖區(qū)讀取數(shù)據(jù)的過程
假如現(xiàn)在有n個生產(chǎn)者(寫入操作),m個消費者(讀取操作),它們都要去操作這塊緩沖區(qū)空間,要注意不能有兩個或多個生產(chǎn)者同時寫數(shù)據(jù),也不能兩個或多個消費者同時讀數(shù)據(jù),因為如果兩個或多個生產(chǎn)者或消費者同時寫入或者讀取數(shù)據(jù),會操作同一塊緩沖區(qū)空間的數(shù)據(jù),這里的消費者讀取數(shù)據(jù)是相當于把數(shù)據(jù)讀走了,也就是把這個數(shù)據(jù)清理掉了,會對別的進程產(chǎn)生影響,所以不可以兩個或多個消費者同時去讀取緩沖區(qū)中數(shù)據(jù)。
首先生產(chǎn)者和消費者對緩沖區(qū)的訪問是一個互斥性訪問,所以不管是生產(chǎn)者往緩沖區(qū)寫入數(shù)據(jù)還是消費者從緩沖區(qū)讀取數(shù)據(jù),都需要通過互斥鎖來控制線程的同步。然后,因為兩個或多個生產(chǎn)者同時向緩沖區(qū)寫入數(shù)據(jù),也不能有兩個或多個消費者從緩沖區(qū)讀取數(shù)據(jù),所以這里需要通過信號量來控制同步。但是要注意設置互斥鎖和信號量的先后順序。
3.生產(chǎn)者和消費者對緩沖區(qū)設置互斥鎖和信號量的思路
(1)設置互斥鎖
對于互斥鎖,無論是消費者還是生產(chǎn)者都應該先看看自己可不可以對緩沖區(qū)進行操作,如果是生產(chǎn)者要先看緩沖區(qū)有沒有剩余空間,如果有剩余空間然后再去加鎖,加了鎖之后就可以保證只有自己在向緩沖區(qū)中寫入數(shù)據(jù);如果是消費者要先看緩沖區(qū)有沒有數(shù)據(jù),如果有數(shù)據(jù)再去加鎖,加了鎖之后就可以保證只有自己在讀取緩沖區(qū)中的數(shù)據(jù)。比如,消費者不可以先對緩沖區(qū)加鎖,因為如果加了所之后再去讀取數(shù)據(jù)的時候發(fā)現(xiàn)緩沖區(qū)沒有數(shù)據(jù),消費者就會被阻塞,但是這時消費者已經(jīng)對緩沖區(qū)加過鎖了,生產(chǎn)者也不可以向緩沖區(qū)中寫入數(shù)據(jù),也會被阻塞。
(2)設置信號量
對于信號量,需要設置兩個信號量,其中一個去控制生產(chǎn)者可不可以向緩沖區(qū)寫入數(shù)據(jù),另一個控制消費者可不可以從緩沖區(qū)讀取數(shù)據(jù)??刂粕a(chǎn)者的信號量的值要參考緩沖區(qū)空間的數(shù)目,要看緩沖區(qū)空間的數(shù)目是幾,生產(chǎn)者信號量的值就是幾,因為可能不只有一個生產(chǎn)者,會有多個生產(chǎn)者。就比如如果把控制生產(chǎn)者的信號量的值設置為1,生產(chǎn)者要向緩沖區(qū)寫入數(shù)據(jù),P操作就會把信號量的值改為0,進行寫入數(shù)據(jù)的操作,這時如果另外一個生產(chǎn)者也要像緩沖區(qū)中寫入數(shù)據(jù),就會失敗,因為此時信號量的值為0,不能再執(zhí)行P操作了??刂葡M者的信號量的值則應該為0,默認情況下緩沖區(qū)沒有數(shù)據(jù),所有消費者都讀取不了數(shù)據(jù)。如下圖:
4.生產(chǎn)者和消費者對緩沖區(qū)設置互斥鎖和信號量的方法
對于生產(chǎn)者來講,要看現(xiàn)在緩沖區(qū)有沒有空間去寫入數(shù)據(jù),生產(chǎn)者首先要對sc_sem這個信號量進行P操作,如果P操作失敗,就說明當前緩沖區(qū)滿,需要等待,如果P操作成功,生產(chǎn)者每次向緩沖區(qū)中寫入數(shù)據(jù),sc_sem這個信號量的值就減1,執(zhí)行完P操作之后,就要向緩沖區(qū)中寫入數(shù)據(jù),這時候要防止別的生產(chǎn)者也要向緩沖區(qū)寫入數(shù)據(jù),所以接下來就要定義一個互斥鎖,執(zhí)行加鎖操作,生產(chǎn)者向緩沖區(qū)中寫完數(shù)據(jù)之后,要進行解鎖操作,這時候其它想要向緩沖區(qū)寫入數(shù)據(jù)的生產(chǎn)者就可以繼續(xù)寫入數(shù)據(jù)了,當所有要向緩沖區(qū)寫入數(shù)據(jù)的生產(chǎn)者都寫完數(shù)據(jù)之后,對xf_sem這個信號量進行V操作,xf_sem這個信號量的值就加1,xf_sem這個信號量的值從0變?yōu)?,這時候消費者就可以工作(從緩沖區(qū)讀取數(shù)據(jù))了。代碼的思路應該是這樣的:
p(sc_sem)
lock(mutex)
write
unlock(mutex)
v(xf_sem)
對于消費者來講,要看當前的緩沖區(qū)中有沒有數(shù)據(jù)可以讀取,消費者首先要對信號量xf_sem進行P操作,如果此時信號量xf_sem為0,也就意味著緩沖區(qū)是空的,P操作執(zhí)行失敗,消費者就會被阻塞,如果信號量xf_sem不為0,消費者才可以對信號量xf_sem進行P操作成功,信號量xf_sem的值減1,這時消費者才可以從緩沖區(qū)讀取數(shù)據(jù),這時要防止別的消費者也要從緩沖區(qū)中讀取數(shù)據(jù)以及生產(chǎn)者想要向緩沖區(qū)中寫入數(shù)據(jù),所以要對緩沖區(qū)加鎖,加鎖之后,消費就可以從緩沖區(qū)中讀取數(shù)據(jù),讀完數(shù)據(jù)之后進行解鎖,這時其他想要從緩沖區(qū)讀取數(shù)據(jù)的消費者就可以繼續(xù)讀取數(shù)據(jù)了,等全部想要讀取數(shù)據(jù)的消費者讀取完之后,緩沖區(qū)就有空閑的空間了,這時對信號量sc_sem進行V操作,信號量sc_sem的值就加1,這時候生產(chǎn)者就可以繼續(xù)對信號量sc_sem進行P操作,重復上面生產(chǎn)者向緩沖區(qū)寫入數(shù)據(jù)的過程。代碼的思路應該是這樣的:
p(xf_sem)
lock(mutex)
read
unlock(mutex)
v(sc_sem)
假設現(xiàn)在有2個生產(chǎn)者,3個消費者,有一個大小為30的緩沖區(qū)。每個生產(chǎn)者向緩沖區(qū)寫入30次數(shù)據(jù),有2個生產(chǎn)者,一共寫入60次數(shù)據(jù),每個消費者從緩沖區(qū)讀取20次數(shù)據(jù),有3個消費者,一共讀取60次數(shù)據(jù)。生產(chǎn)者一共向緩沖區(qū)寫入60次數(shù)據(jù),消費者一共從緩沖區(qū)讀取了60次數(shù)據(jù),這個過程結(jié)束之后,緩沖區(qū)為空。
代碼如下:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>
#include<semaphore.h>
#define BUFF_MAX 30 //緩沖區(qū)的大小
int buff[BUFF_MAX]; //緩沖區(qū)
int in = 0;//寫入數(shù)據(jù)的下標
int out = 0;//讀取數(shù)據(jù)的下標
pthread_mutex_t mutex;//定義一個鎖變量
sem_t sc_sem;//定義一個信號量,用來控制生產(chǎn)者
sem_t xf_sem;//定義一個信號量,用來控制消費者
void* sc_fun(void*arg)//生產(chǎn)者線程函數(shù)
{
for(int i=0;i<30;i++)//一個生產(chǎn)者線程寫入30次,有2個生產(chǎn)者,一共寫入60次數(shù)據(jù)
{
sem_wait(&sc_sem);//對控制生產(chǎn)者的信號量sc_sem進行P操作
pthread_mutex_lock(&mutex);//加鎖
//隨機產(chǎn)生一個數(shù)據(jù)再寫入
buff[in]=rand()%100;//產(chǎn)生一個100以內(nèi)的隨機數(shù),將其寫入緩沖區(qū)
printf("生產(chǎn)者向緩存區(qū)中寫入數(shù)據(jù)%d,在%d下標寫入\n",buff[in],in);
in=(in+1)%BUFF_MAX;//更新in的下標
pthread_mutex_unlock(&mutex);//解鎖
sem_post(&xf_sem);//對控制消費者的信號量xf_sem進行V操作
int n=rand()%3;//產(chǎn)生一個3以內(nèi)的隨機數(shù)
sleep(n);/*睡眠3秒以內(nèi),為了不讓當前的生產(chǎn)者繼續(xù)對信號量sc_sem進行P操作,
給其他生產(chǎn)者向緩沖區(qū)寫入數(shù)據(jù)的機會,讓結(jié)果看著更隨機*/
}
}
void* xf_fun(void* arg)//消費者線程函數(shù)
{
for(int i=0;i<20;i++)//一個消費者線程讀取20次,有3個消費者,一共讀取60次數(shù)據(jù)
{
sem_wait(&xf_sem);//對控制消費者的信號量xf_sem進行P操作
pthread_mutex_lock(&mutex);//加鎖
printf("消費者從緩沖區(qū)讀取數(shù)據(jù)%d,在%d下標讀取\n",buff[out],out);
out=(1+out)%BUFF_MAX;
pthread_mutex_unlock(&mutex);
sem_post(&sc_sem);
int n=rand()%3;
sleep(3);
}
}
int main()
{
pthread_mutex_init(&mutex,NULL);//初始化互斥鎖
sem_init(&sc_sem,0,BUFF_MAX);//初始化sc_sem信號量
sem_init(&xf_sem,0,BUFF_MAX);//初始化xf_sem信號量
srand((int)time(NULL));//隨機種子
pthread_t sc_id[2];//定義2個生產(chǎn)者線程
for(int i=0;i<2;i++)//創(chuàng)建并啟動這兩個生產(chǎn)者線程
{
pthread_create(&sc_id[i],NULL,sc_fun,NULL);
}
pthread_t xf_id[3];//定義3個消費者線程
for(int i=0;i<3;i++)
{
pthread_create(&xf_id[i],NULL,xf_fun,NULL);
}
for(int i=0;i<2;i++)
{
pthread_join(sc_id[i],NULL);//等待2個生產(chǎn)者線程結(jié)束
}
for(int i=0;i<3;i++)
{
pthread_join(xf_id[i],NULL);//等待3個消費者線程結(jié)束
}
sem_destroy(&sc_sem);//銷毀生產(chǎn)者信號量
sem_destroy(&xf_sem);//銷毀消費者信號量
pthread_mutex_destroy(&mutex);//銷毀鎖
exit(0);
}
部分運行結(jié)果如下:
因篇幅問題不能全部顯示,請點此查看更多更全內(nèi)容
Copyright ? 2019- 91gzw.com 版權所有 湘ICP備2023023988號-2
違法及侵權請聯(lián)系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市萬商天勤律師事務所王興未律師提供法律服務