生產者消費者問題

一、實驗目的
學習生產者與消費者的運行基本原理,學習使用共享內存區,學習使用多進程,學會使用鎖互斥訪問對象。
二、實驗內容
一個大小爲3的緩衝區,初始爲空
•2個生產者
–隨機等待一段時間,往緩衝區添加數據,
–若緩衝區已滿,等待消費者取走數據後再添加
–重複6次
•3個消費者
–隨機等待一段時間,從緩衝區讀取數據
–若緩衝區爲空,等待生產者添加數據後再讀取
–重複4次
說明:
•顯示每次添加和讀取數據的時間及緩衝區的狀態
•生產者和消費者用進程模擬,緩衝區用共享內存來實現
三、實驗環境
Windows7和Ubuntu10.10
四、程序設計與實現
生產者的算法流程:                   消費者算法流程:
P(empty)                          P(full)
P(mutex);                           P(mutex);
生產                                消費
V(full)                             V(empty)
V(mutex);                           V(mutex);
 
  
主要算法爲主程序先建立鎖和共享內存區,然後調用自身形成兩個生產者和三個消費者,生產者和消費者請求信號量,請求滿足後,打開共享內存區獲得數據,如果滿足生產或消費條件,就修改數據,然後釋放信號量。
我編寫程序的主要機制是生產者生產數據後放入隊列,消費者從隊列消費,1表示有數據,0表示無數據。windows下我還使用了WaitForMultObjects函數,用以同步各進程狀態。
Windows:
利用下面的函數建立生產者和消費者的進程。
BOOL CreateProcess (
  LPCTSTR lpApplicationName,
  LPTSTR lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes。
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL bInheritHandles,
  DWORD dwCreationFlags,
  LPVOID lpEnvironment,
  LPCTSTR lpCurrentDirectory,
  LPSTARTUPINFO lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);
在主進程中使用下面的函數建立文件映射對象:
HANDLE CreateFileMapping(
  HANDLE hFile,                       // handle to file
  LPSECURITY_ATTRIBUTES lpAttributes, // security
  DWORD flProtect,                    // protection
  DWORD dwMaximumSizeHigh,            // high-order DWORD of size
  DWORD dwMaximumSizeLow,             // low-order DWORD of size
  LPCTSTR lpName                      // object name
);
在每個生產者與消費者進程中利用下面的函數打開文件映射對象:
HANDLE OpenFileMapping(
  DWORD dwDesiredAccess,  // access mode
  BOOL bInheritHandle,    // inherit flag
  LPCTSTR lpName          // object name
);
把文件映射到進程的地址空間的函數:
LPVOID MapViewOfFile(
  HANDLE hFileMappingObject,   // handle to file-mapping object
  DWORD dwDesiredAccess,       // access mode
  DWORD dwFileOffsetHigh,      // high-order DWORD of offset
  DWORD dwFileOffsetLow,       // low-order DWORD of offset
  SIZE_T dwNumberOfBytesToMap  // number of bytes to map
);
解除一個文件對象的映射函數:
BOOL UnmapViewOfFile(
  LPCVOID lpBaseAddress   // starting address
);
使用內存文件映射的步驟:
1. 通過CreateFile()函數來創建或打開一個文件的內核對象,這個對象標示了磁盤上將要用作內存映射的文件,通過實驗可以知道這步可以省略。
2. 通過CreateFileMapping()函數來建立一個文件映射內核對象。
3. MapViewOfFile()函數間該文件映射對象的全部或部分映射到進程地址空間。
用讀寫內存的方式操作和處理文件數據。
4. 在使用完內存映射文件後,通過UnmapViewOfFile()函數完成從進程的地址空間撤銷文件數據的映像。
5. 通過CloseHandle()函數關閉創建的文件映射對象和文件對象,清除和釋放所使用過的資源。
使用下面的函數建立鎖:
HANDLE CreateMutex(
  LPSECURITY_ATTRIBUTES lpMutexAttributes, //指向安全屬性的指針
  BOOL bInitialOwner, // 初始化互斥對象的所有者
  LPCTSTR lpName //指向互斥對象名的指針
);
在使用的時候利用一下函數打開鎖:
HANDLE OpenMutex(
  DWORD dwDesiredAccess,  // access
  BOOL bInheritHandle,    // inheritance option
  LPCTSTR lpName          // object name
);
使用WaitSingleObject函數等待。
運行如下:
Linux:
使用fork()函數建立生產者與消費者,然後和windows算法基本相似,在加鎖後操作內存共享區。
shmget(key,size,shmflg)key爲關鍵字,size爲大小,shmflg爲訪問權限的標誌
shmat(shmid,shmadd,shmflg)利用這個函數將共享段添加到申請通信的進程空間。
shmdt(shmaddr)將共享內存區解除連接,shmaddr爲進程空間的虛地址。
shmctl(int shmid,int cmd,struct shmid_ds *buf)
semget(key_t key,int nsems,int semflg)建立信號量
semop(int semid,struct sembuf *sops,unsigned nsops)操作信號量
semctl(int semid,int semnum,int cmd,union semun arg)控制信號量,執行P/V操作。
 

 

windows代碼

 

  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <time.h>
  4. static HANDLE hMutexMapping=INVALID_HANDLE_VALUE;
  5. int num=0;
  6. HANDLE lpHandle[10];
  7. struct buf
  8. {
  9. int num;
  10. int read;
  11. int write;
  12. int buffer[5];
  13. };
  14. BOOL StartClone()
  15. {
  16. int i;
  17. BOOL bCreateOK;
  18. PROCESS_INFORMATION pi;
  19. TCHAR szFilename[MAX_PATH];
  20. GetModuleFileName(NULL,szFilename,MAX_PATH);
  21. TCHAR szCmdLine[MAX_PATH];
  22. for ( i = 0; i < 3; i++)
  23. {
  24. sprintf(szCmdLine,"\"%s\" consumer %d",szFilename,i);
  25. STARTUPINFO si;
  26. ZeroMemory(reinterpret_cast<void *>(&si),sizeof(si));
  27. si.cb=sizeof(si);
  28. bCreateOK=CreateProcess(
  29. szFilename,
  30. szCmdLine,
  31. NULL,
  32. NULL,
  33. FALSE,
  34. CREATE_DEFAULT_ERROR_MODE,
  35. NULL,
  36. NULL,
  37. &si,
  38. &pi);
  39. if (!bCreateOK)
  40. {
  41. return false;
  42. }
  43. lpHandle[num]=pi.hProcess;
  44. num++;
  45. }
  46. for ( i = 0; i < 2; i++)
  47. {
  48. sprintf(szCmdLine,"\"%s\" productor %d",szFilename,i);
  49. STARTUPINFO si;
  50. ZeroMemory(reinterpret_cast<void *>(&si),sizeof(si));
  51. si.cb=sizeof(si);
  52. bCreateOK=CreateProcess(
  53. szFilename,
  54. szCmdLine,
  55. NULL,
  56. NULL,
  57. FALSE,
  58. CREATE_DEFAULT_ERROR_MODE,
  59. NULL,
  60. NULL,
  61. &si,
  62. &pi);
  63. if (!bCreateOK)
  64. {
  65. return false;
  66. }
  67. lpHandle[num]=pi.hProcess;
  68. num++;
  69. }
  70. return true;
  71. }
  72. void Parent()
  73. {
  74. printf("Creating the child process and waited child process to quit.\n");
  75. hMutexMapping=CreateMutex(NULL,true,"mutex");
  76. HANDLE hMapping=CreateFileMapping(
  77. NULL,
  78. NULL,
  79. PAGE_READWRITE,
  80. 0,
  81. sizeof(LONG),
  82. "map");
  83. if (hMapping!=INVALID_HANDLE_VALUE)
  84. {
  85. LPVOID pData=MapViewOfFile(
  86. hMapping,
  87. FILE_MAP_ALL_ACCESS,
  88. 0,
  89. 0,
  90. 0);
  91. if (pData!=NULL)
  92. {
  93. ZeroMemory(pData,sizeof(LONG));
  94. }
  95. struct buf *pnData=reinterpret_cast<struct buf *>(pData);
  96. pnData->read=0;
  97. pnData->write=0;
  98. pnData->num=0;
  99. memset(pnData->buffer,0,sizeof(pnData->buffer));
  100. UnmapViewOfFile(pData);
  101. }
  102. CreateSemaphore(NULL,3,3,"EMPTY");
  103. CreateSemaphore(NULL,0,3,"FULL");
  104. BOOL bCreateOK=StartClone();
  105. if (!bCreateOK)
  106. {
  107. //printf("Create child process failed.\n");
  108. }
  109. else
  110. {
  111. //printf("Create child process success.\n");
  112. }
  113. ReleaseMutex(hMutexMapping);
  114. }
  115. void Productor(int n)
  116. {
  117. int j;
  118. printf("Productor is running.\n");
  119. hMutexMapping=OpenMutex(MUTEX_ALL_ACCESS,true,"mutex");
  120. HANDLE hMapping=OpenFileMapping(
  121. FILE_MAP_ALL_ACCESS,
  122. NULL,
  123. "map");
  124. if (hMapping==INVALID_HANDLE_VALUE)
  125. {
  126. printf("error\n");
  127. }
  128. HANDLE semEmpty = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"EMPTY");
  129. HANDLE semFull = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"FULL");
  130. for (int i = 0; i < 6; i++)
  131. {
  132. WaitForSingleObject(semEmpty, INFINITE);
  133. SYSTEMTIME st;
  134. GetSystemTime(&st);
  135. srand((unsigned)time(0));
  136. Sleep(rand()/6);
  137. WaitForSingleObject(hMutexMapping,INFINITE);
  138. LPVOID pFile=MapViewOfFile(
  139. hMapping,
  140. FILE_MAP_ALL_ACCESS,
  141. 0,
  142. 0,
  143. 0);
  144. if (pFile!=NULL)
  145. {
  146. struct buf *pnData=reinterpret_cast<struct buf *>(pFile);
  147. pnData->buffer[pnData->write]=1;
  148. pnData->write=(pnData->write+1)%3;
  149. pnData->num++;
  150. printf("%02d:%02d:%02d 生產者[%d]生產成功 緩衝區中剩餘%d個 ",st.wHour,st.wMinute,st.wSecond,n,pnData->num);
  151. for (j = 0; j < 3; j++)
  152. {
  153. printf("%d ",pnData->buffer[j]);
  154. }
  155. printf("\n");
  156. }
  157. UnmapViewOfFile(pFile);
  158. pFile=NULL;
  159. ReleaseSemaphore(semFull, 1, NULL);
  160. ReleaseMutex(hMutexMapping);
  161. }
  162. printf("生產者[%d]生產完畢\n",n);
  163. }
  164. void Consumer(int n)
  165. {
  166. int j;
  167. printf("Consumer is running.\n");
  168. hMutexMapping=OpenMutex(MUTEX_ALL_ACCESS,true,"mutex");
  169. HANDLE hMapping=OpenFileMapping(
  170. FILE_MAP_ALL_ACCESS,
  171. NULL,
  172. "map");
  173. if (hMapping==INVALID_HANDLE_VALUE)
  174. {
  175. printf("error\n");
  176. }
  177. HANDLE semEmpty = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"EMPTY");
  178. HANDLE semFull = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"FULL");
  179. for (int i = 0; i < 4; i++)
  180. {
  181. WaitForSingleObject(semFull, INFINITE);
  182. SYSTEMTIME st;
  183. GetSystemTime(&st);
  184. srand((unsigned)time(0));
  185. Sleep(rand()/6);
  186. WaitForSingleObject(hMutexMapping,INFINITE);
  187. LPVOID pFile=MapViewOfFile(
  188. hMapping,
  189. FILE_MAP_ALL_ACCESS,
  190. 0,
  191. 0,
  192. 0);
  193. if (pFile!=NULL)
  194. {
  195. struct buf *pnData=reinterpret_cast<struct buf *>(pFile);
  196. pnData->buffer[pnData->read]=0;
  197. pnData->read=(pnData->read+1)%3;
  198. pnData->num--;
  199. printf("%02d:%02d:%02d 消費者[%d]消費成功 緩衝區中剩餘%d個 ",st.wHour,st.wMinute,st.wSecond,n,pnData->num);
  200. for (j = 0; j < 3; j++)
  201. {
  202. printf("%d ",pnData->buffer[j]);
  203. }
  204. printf("\n");
  205. }
  206. UnmapViewOfFile(pFile);
  207. pFile=NULL;
  208. ReleaseSemaphore(semEmpty,1,NULL);
  209. ReleaseMutex(hMutexMapping);
  210. }
  211. printf("消費者[%d]消費完畢\n",n);
  212. }
  213. int main(int argc,char **argv)
  214. {
  215. if (argc>1&&strcmp(argv[1],"productor")==0)
  216. {
  217. Productor(atoi(argv[2]));
  218. }
  219. else if (argc>1&&strcmp(argv[1],"consumer")==0)
  220. {
  221. Consumer(atoi(argv[2]));
  222. }
  223. else
  224. {
  225. Parent();
  226. WaitForMultipleObjects(num,lpHandle,true,INFINITE);
  227. }
  228. return 0;
  229. }

linux代碼:

main.c文件

  1. #include <math.h>  
  2. #include <stdio.h>  
  3. #include <sys/time.h>  
  4. #include <time.h>  
  5. #include <sys/types.h>  
  6. #include <sys/ipc.h>  
  7. #include <sys/shm.h>  
  8. #include <sys/wait.h>  
  9. #include <sys/sem.h>  
  10. #include <stdlib.h>  
  11. #define SHMKEY 75  
  12. #define K 1024  
  13. #define SEM_ID 225  
  14. #define SEM_FULL 128  
  15. #define SEM_EMPTY 256  
  16.  
  17. int shmid;  
  18. int sem_set_id;  
  19. int sem_full;  
  20. int sem_empty;  
  21. union   semun  
  22. {  
  23.     int   val;  
  24.     struct   semid_ds   *buf;  
  25.     unsigned   short   int   *array;  
  26.     struct   seminfo   *__buf;  
  27. };  
  28. struct buf  
  29. {  
  30.     int num;  
  31.     int read;  
  32.     int write;  
  33.     int buffer[5];  
  34. };  
  35.  
  36. void Producer()  
  37. {  
  38.     int i;  
  39.     char argv[2];  
  40.     for (i = 0; i < 2; i++)  
  41.     {  
  42.         if (fork()==0)  
  43.         {  
  44.             argv[0]=i+48;  
  45.             argv[1]=0;  
  46.             //printf("%s\n",argv);  
  47.             execl("productor","productor",argv,(char*)0);  
  48.             exit(0);  
  49.         }  
  50.     }  
  51. }  
  52.  
  53. void Consumer()  
  54. {  
  55.     int i;  
  56.     char argv[2];  
  57.     for (i = 0; i < 3; i++)  
  58.     {  
  59.         if (fork()==0)  
  60.         {  
  61.             argv[0]=i+48;  
  62.             argv[1]=0;  
  63.             //printf("%s\n",argv);  
  64.             execl("consumer","consumer",argv,0);  
  65.             exit(0);  
  66.         }  
  67.     }  
  68. }  
  69.  
  70. int main(int argc,int **argv)  
  71. {  
  72.     int i,rc;  
  73.     struct buf *pint;  
  74.     char *addr;  
  75.     union semun sem_val;  
  76.     sem_set_id=semget(SEM_ID,1,IPC_CREAT|0600);  
  77.     sem_full=semget(SEM_FULL,3,IPC_CREAT|0600);  
  78.     sem_empty=semget(SEM_EMPTY,3,IPC_CREAT|0600);  
  79.     sem_val.val=1;  
  80.     rc=semctl(sem_set_id,0,SETVAL,sem_val);  
  81.     sem_val.val=3;  
  82.     rc=semctl(sem_empty,0,SETVAL,sem_val);  
  83.     sem_val.val=0;  
  84.     rc=semctl(sem_full,0,SETVAL,sem_val);  
  85.     shmid=shmget(SHMKEY,K,0777|IPC_CREAT);  
  86.     addr=shmat(shmid,0,0);  
  87.     pint=(struct buf *)addr;  
  88.     memset(addr,0,512);  
  89.     shmdt(addr);  
  90.     Producer();  
  91.     Consumer();  
  92.     printf("Create success!\n");  
  93.     return 0;  
  94. }  

consumer.c文件

 

  1. #include <math.h>  
  2. #include <stdio.h>  
  3. #include <sys/time.h>  
  4. #include <time.h>  
  5. #include <sys/types.h>  
  6. #include <sys/ipc.h>  
  7. #include <sys/shm.h>  
  8. #include <sys/wait.h>  
  9. #include <sys/sem.h>  
  10. #define SHMKEY 75  
  11. #define K 1024  
  12. #define SEM_ID 225  
  13. #define SEM_FULL 128  
  14. #define SEM_EMPTY 256  
  15.    
  16. int shmid;  
  17. int sem_set_id;  
  18. int sem_full;  
  19. int sem_empty;  
  20. union   semun  
  21. {  
  22.     int   val;  
  23.     struct   semid_ds   *buf;  
  24.     unsigned   short   int   *array;  
  25.     struct   seminfo   *__buf;  
  26. };  
  27. struct buf  
  28. {  
  29.     int num;  
  30.     int read;  
  31.     int write;  
  32.     int buffer[5];  
  33. };  
  34. int main(int argc,char *argv[])  
  35. {  
  36.     int i,j,r;  
  37.     struct buf *pint;  
  38.     char *addr;  
  39.     struct sembuf sem_op;  
  40.     int n;  
  41.     n=atoi(argv[1]);  
  42.     printf("success!\n");  
  43.     sem_set_id=semget(SEM_ID,1,0600);  
  44.     sem_full=semget(SEM_FULL,1,0600);  
  45.     sem_empty=semget(SEM_EMPTY,1,0600);  
  46.     for (i = 0; i < 4; i++)  
  47.     {  
  48.         sem_op.sem_num=0;  
  49.         sem_op.sem_op=-1;  
  50.         sem_op.sem_flg=0;  
  51.         semop(sem_full,&sem_op,1);  
  52.         srand((unsigned)time(0));  
  53.         do 
  54.         {  
  55.             r=rand()%5;  
  56.         }  
  57.         while(r==0);  
  58.         //printf("%d\n",rand()%5);  
  59.         sleep(r);  
  60.         sem_op.sem_num=0;  
  61.         sem_op.sem_op=-1;  
  62.         sem_op.sem_flg=0;  
  63.         semop(sem_set_id,&sem_op,1);  
  64.         time_t now;  
  65.         struct tm *timenow;  
  66.         time(&now);  
  67.         timenow=localtime(&now);  
  68.         shmid=shmget(SHMKEY,K,0777);  
  69.         if (shmid<0)  
  70.         {  
  71.             printf("shmget error\n");  
  72.             exit(-1);  
  73.         }  
  74.         addr=shmat(shmid,0,0);  
  75.         pint=(struct buf *)addr;  
  76.         pint->buffer[pint->read]=0;  
  77.         pint->read=(pint->read+1)%3;  
  78.         pint->num--;  
  79.         printf("%02d:%02d:%02d   Consumer[%d]success  %dleft ",timenow->tm_hour,timenow->tm_min,timenow->tm_sec,n,pint->num);  
  80.         for (j = 0; j < 3; j++)  
  81.         {  
  82.             printf("%d ",pint->buffer[j]);  
  83.         }  
  84.         printf("\n");  
  85.         shmdt(addr);  
  86.         sem_op.sem_num=0;  
  87.         sem_op.sem_op=1;  
  88.         sem_op.sem_flg=0;  
  89.         semop(sem_empty,&sem_op,1);  
  90.         sem_op.sem_num=0;  
  91.         sem_op.sem_op=1;  
  92.         sem_op.sem_flg=0;  
  93.         semop(sem_set_id,&sem_op,1);  
  94.     }  
  95.     printf("Consumer %d exit\n",n);  
  96.     return 0;  
  97. }  

productor.c

 

  1. #include <math.h>  
  2. #include <stdio.h>  
  3. #include <sys/time.h>  
  4. #include <time.h>  
  5. #include <sys/types.h>  
  6. #include <sys/ipc.h>  
  7. #include <sys/shm.h>  
  8. #include <sys/wait.h>  
  9. #include <sys/sem.h>  
  10. #define SHMKEY 75  
  11. #define K 1024  
  12. #define SEM_ID 225  
  13. #define SEM_FULL 128  
  14. #define SEM_EMPTY 256  
  15.  
  16. int shmid;  
  17. int sem_set_id;  
  18. int sem_full;  
  19. int sem_empty;  
  20. union   semun  
  21. {  
  22.     int   val;  
  23.     struct   semid_ds   *buf;  
  24.     unsigned   short   int   *array;  
  25.     struct   seminfo   *__buf;  
  26. };  
  27. struct buf  
  28. {  
  29.     int num;  
  30.     int read;  
  31.     int write;  
  32.     int buffer[5];  
  33. };  
  34. int main(int argc,char *argv[])  
  35. {  
  36.     int i,j,r;  
  37.     struct buf *pint;  
  38.     char *addr;  
  39.     struct sembuf sem_op;  
  40.     int n;  
  41.     n=atoi(argv[1]);  
  42.     printf("success!\n");  
  43.     sem_set_id=semget(SEM_ID,1,0600);  
  44.     sem_full=semget(SEM_FULL,1,0600);  
  45.     sem_empty=semget(SEM_EMPTY,1,0600);  
  46.     for (i = 0; i < 6; i++)  
  47.     {  
  48.         sem_op.sem_num=0;  
  49.         sem_op.sem_op=-1;  
  50.         sem_op.sem_flg=0;  
  51.         semop(sem_empty,&sem_op,1);  
  52.         srand((unsigned)time(0));  
  53.         do 
  54.         {  
  55.             r=rand()%5;  
  56.         }  
  57.         while(r==0);  
  58.         sleep(r);  
  59.         sem_op.sem_num=0;  
  60.         sem_op.sem_op=-1;  
  61.         sem_op.sem_flg=0;  
  62.         semop(sem_set_id,&sem_op,1);  
  63.         time_t now;  
  64.         struct tm *timenow;  
  65.         time(&now);  
  66.         timenow=localtime(&now);  
  67.         shmid=shmget(SHMKEY,K,0777);  
  68.         if (shmid<0)  
  69.         {  
  70.             printf("shmget error\n");  
  71.             exit(-1);  
  72.         }  
  73.         addr=shmat(shmid,0,0);  
  74.         pint=(struct buf *)addr;  
  75.         pint->buffer[pint->write]=1;  
  76.         pint->write=(pint->write+1)%3;  
  77.         pint->num++;  
  78.         printf("%02d:%02d:%02d   Producer[%d]success  %dleft ",timenow->tm_hour,timenow->tm_min,timenow->tm_sec,n,pint->num);  
  79.         for (j = 0; j < 3; j++)  
  80.         {  
  81.             printf("%d ",pint->buffer[j]);  
  82.         }  
  83.         printf("\n");  
  84.         shmdt(addr);  
  85.         sem_op.sem_num=0;  
  86.         sem_op.sem_op=1;  
  87.         sem_op.sem_flg=0;  
  88.         semop(sem_full,&sem_op,1);  
  89.         sem_op.sem_num=0;  
  90.         sem_op.sem_op=1;  
  91.         sem_op.sem_flg=0;  
  92.         semop(sem_set_id,&sem_op,1);  
  93.     }  
  94.     printf("Productor %d exit\n",n);  
  95.     return 0;  
  96. }  
  97.    

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章