生產者消費者模型已經很古老了吧,最近寫了個OpenMP版的此模型之實現,來分享下。
先說一下模型的大致做法是:
1、生產者需要取任務,生產產品。
2、消費者需要取產品,消費產品。
生產者在生產某個產品之后,要告知消費者此產品已經可以使用了。消費者通過獲得可以使用這個信號來取得產品,進一步消費產品。
比如,我們有N個圖像需要對每一個圖像作濾波或者變換等處理,并且把處理后的結果存到硬盤上。
那么生產者可以將N個圖像看成N個任務,每個任務都是獨立的,每個任務的計算結果可以看成是產品,消費者就是取這個產品來寫入硬盤。
先貼出一個實例代碼再作解釋。
#include#include#include#include#include#define?jobs?1000
#define?sz?102000
#if?defined(_WIN32)?&&?defined(_MSC_VER)
#includedouble?abtic()?{
__int64?freq;
__int64?clock;
QueryPerformanceFrequency(?(LARGE_INTEGER?*)&freq?);
QueryPerformanceCounter(?(LARGE_INTEGER?*)&clock?);
return?(double)clock/freq*1000*1000;
}
#else
#include#includedouble?abtic()?{
double?result?=?0.0;
struct?timeval?tv;
gettimeofday(?&tv,?NULL?);
result?=?tv.tv_sec*1000*1000?+?tv.tv_usec;
return?result;
}
#endif?/*?_WIN32?*/
#if?1
double?timer;
#define?ABTMS?timer=abtic();fprintf(stdout,"%4d??",__LINE__)
#define?ABTME?fprintf(stdout,"%4d??%8.8fmsn",__LINE__,(abtic()-timer)/1000.0f)
#else
#define?ABTMS?
#define?ABTME?
#endif
int?main()
{
??char?*jbNotReady;
??double?*a;
??double?*as;
??double?*pa;
??int?j,?k;
char?jbnr;
??a?=?(double*)malloc(sz*jobs*sizeof(double));
??as?=?(double*)malloc(jobs*sizeof(double));
??jbNotReady?=?(char*)malloc(jobs*sizeof(char));
??for?(j?=?0;?j?<?jobs;?j++)
??{
????jbNotReady[j]?=?1;
????
??}
??memset(a,?0,?sz*jobs*sizeof(double));
??memset(as,?0,?jobs*sizeof(double));
??ABTMS;
#pragma?omp?parallel?sections?private(j,k,pa)?shared(jbNotReady,as,a)
??{
????//?producer
#pragma?omp?section
????{
??????for?(j?=?0;?j?<?jobs;?j++)
??????{
????????pa?=?a+j*sz;
????????for?(k?=?0;?k?<?sz;?k++)
????????{
??????????pa[k]?=?1.0;
????????}
????????jbNotReady[j]?=?0;
#pragma?omp?flush
??????}
????}
????//?consumer
#pragma?omp?section
????{
??????for?(j?=?0;?j?<?jobs;?j++)
??????{
#pragma?omp?flush
????????while?(jbNotReady[j]){
#pragma?omp?flush
}
????????as[j]?=?0.0;
????????pa?=?a+j*sz;
????????for?(k?=?0;?k?<?sz;?k++)
????????{
??????????as[j]?+=?pa[k];
????????}
????????if?((int)(as[j])!=sz)fprintf(stdout,?"job?id?%3d?:%fn",?j,?as[j]);
??????}
????}
??}
??ABTME;
??free(a);
??free(as);
??free(jbNotReady);
??return?0;
}
源代碼中,第一個section創(chuàng)建的線程扮演的就是生產者的角色,第二個section扮演消費者角色。j這個變量模擬的是任務編號,第一個section中的循環(huán)模擬產生產品。第二個section每次取一個任務,而且是順序取,通過驗證任務是否已經準備好來獲得正確的產品。
使用flush制導語句是為了將每個線程的緩存和內存強制保持一致,注意生產者向jbNotReady里寫,而消費者只是讀數據,不會出現內存中的數據寫后讀,讀后寫的問題,每個線程獲得的數據都是安全的。
以上代碼支持Windows和Linux,GCC4.4以后的版本都可以執(zhí)行,Windows下只要支持OpenMP的編譯器,都可行。





