一、實驗目的
學習生產者與消費者的運行基本原理,學習使用共享內存區,學習使用多進程,學會使用鎖互斥訪問對象。
二、實驗內容
一個大小爲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代碼
- #include <stdio.h>
- #include <windows.h>
- #include <time.h>
- static HANDLE hMutexMapping=INVALID_HANDLE_VALUE;
- int num=0;
- HANDLE lpHandle[10];
- struct buf
- {
- int num;
- int read;
- int write;
- int buffer[5];
- };
- BOOL StartClone()
- {
- int i;
- BOOL bCreateOK;
- PROCESS_INFORMATION pi;
- TCHAR szFilename[MAX_PATH];
- GetModuleFileName(NULL,szFilename,MAX_PATH);
- TCHAR szCmdLine[MAX_PATH];
- for ( i = 0; i < 3; i++)
- {
- sprintf(szCmdLine,"\"%s\" consumer %d",szFilename,i);
- STARTUPINFO si;
- ZeroMemory(reinterpret_cast<void *>(&si),sizeof(si));
- si.cb=sizeof(si);
- bCreateOK=CreateProcess(
- szFilename,
- szCmdLine,
- NULL,
- NULL,
- FALSE,
- CREATE_DEFAULT_ERROR_MODE,
- NULL,
- NULL,
- &si,
- &pi);
- if (!bCreateOK)
- {
- return false;
- }
- lpHandle[num]=pi.hProcess;
- num++;
- }
- for ( i = 0; i < 2; i++)
- {
- sprintf(szCmdLine,"\"%s\" productor %d",szFilename,i);
- STARTUPINFO si;
- ZeroMemory(reinterpret_cast<void *>(&si),sizeof(si));
- si.cb=sizeof(si);
- bCreateOK=CreateProcess(
- szFilename,
- szCmdLine,
- NULL,
- NULL,
- FALSE,
- CREATE_DEFAULT_ERROR_MODE,
- NULL,
- NULL,
- &si,
- &pi);
- if (!bCreateOK)
- {
- return false;
- }
- lpHandle[num]=pi.hProcess;
- num++;
- }
- return true;
- }
- void Parent()
- {
- printf("Creating the child process and waited child process to quit.\n");
- hMutexMapping=CreateMutex(NULL,true,"mutex");
- HANDLE hMapping=CreateFileMapping(
- NULL,
- NULL,
- PAGE_READWRITE,
- 0,
- sizeof(LONG),
- "map");
- if (hMapping!=INVALID_HANDLE_VALUE)
- {
- LPVOID pData=MapViewOfFile(
- hMapping,
- FILE_MAP_ALL_ACCESS,
- 0,
- 0,
- 0);
- if (pData!=NULL)
- {
- ZeroMemory(pData,sizeof(LONG));
- }
- struct buf *pnData=reinterpret_cast<struct buf *>(pData);
- pnData->read=0;
- pnData->write=0;
- pnData->num=0;
- memset(pnData->buffer,0,sizeof(pnData->buffer));
- UnmapViewOfFile(pData);
- }
- CreateSemaphore(NULL,3,3,"EMPTY");
- CreateSemaphore(NULL,0,3,"FULL");
- BOOL bCreateOK=StartClone();
- if (!bCreateOK)
- {
- //printf("Create child process failed.\n");
- }
- else
- {
- //printf("Create child process success.\n");
- }
- ReleaseMutex(hMutexMapping);
- }
- void Productor(int n)
- {
- int j;
- printf("Productor is running.\n");
- hMutexMapping=OpenMutex(MUTEX_ALL_ACCESS,true,"mutex");
- HANDLE hMapping=OpenFileMapping(
- FILE_MAP_ALL_ACCESS,
- NULL,
- "map");
- if (hMapping==INVALID_HANDLE_VALUE)
- {
- printf("error\n");
- }
- HANDLE semEmpty = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"EMPTY");
- HANDLE semFull = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"FULL");
- for (int i = 0; i < 6; i++)
- {
- WaitForSingleObject(semEmpty, INFINITE);
- SYSTEMTIME st;
- GetSystemTime(&st);
- srand((unsigned)time(0));
- Sleep(rand()/6);
- WaitForSingleObject(hMutexMapping,INFINITE);
- LPVOID pFile=MapViewOfFile(
- hMapping,
- FILE_MAP_ALL_ACCESS,
- 0,
- 0,
- 0);
- if (pFile!=NULL)
- {
- struct buf *pnData=reinterpret_cast<struct buf *>(pFile);
- pnData->buffer[pnData->write]=1;
- pnData->write=(pnData->write+1)%3;
- pnData->num++;
- printf("%02d:%02d:%02d 生產者[%d]生產成功 緩衝區中剩餘%d個 ",st.wHour,st.wMinute,st.wSecond,n,pnData->num);
- for (j = 0; j < 3; j++)
- {
- printf("%d ",pnData->buffer[j]);
- }
- printf("\n");
- }
- UnmapViewOfFile(pFile);
- pFile=NULL;
- ReleaseSemaphore(semFull, 1, NULL);
- ReleaseMutex(hMutexMapping);
- }
- printf("生產者[%d]生產完畢\n",n);
- }
- void Consumer(int n)
- {
- int j;
- printf("Consumer is running.\n");
- hMutexMapping=OpenMutex(MUTEX_ALL_ACCESS,true,"mutex");
- HANDLE hMapping=OpenFileMapping(
- FILE_MAP_ALL_ACCESS,
- NULL,
- "map");
- if (hMapping==INVALID_HANDLE_VALUE)
- {
- printf("error\n");
- }
- HANDLE semEmpty = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"EMPTY");
- HANDLE semFull = OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"FULL");
- for (int i = 0; i < 4; i++)
- {
- WaitForSingleObject(semFull, INFINITE);
- SYSTEMTIME st;
- GetSystemTime(&st);
- srand((unsigned)time(0));
- Sleep(rand()/6);
- WaitForSingleObject(hMutexMapping,INFINITE);
- LPVOID pFile=MapViewOfFile(
- hMapping,
- FILE_MAP_ALL_ACCESS,
- 0,
- 0,
- 0);
- if (pFile!=NULL)
- {
- struct buf *pnData=reinterpret_cast<struct buf *>(pFile);
- pnData->buffer[pnData->read]=0;
- pnData->read=(pnData->read+1)%3;
- pnData->num--;
- printf("%02d:%02d:%02d 消費者[%d]消費成功 緩衝區中剩餘%d個 ",st.wHour,st.wMinute,st.wSecond,n,pnData->num);
- for (j = 0; j < 3; j++)
- {
- printf("%d ",pnData->buffer[j]);
- }
- printf("\n");
- }
- UnmapViewOfFile(pFile);
- pFile=NULL;
- ReleaseSemaphore(semEmpty,1,NULL);
- ReleaseMutex(hMutexMapping);
- }
- printf("消費者[%d]消費完畢\n",n);
- }
- int main(int argc,char **argv)
- {
- if (argc>1&&strcmp(argv[1],"productor")==0)
- {
- Productor(atoi(argv[2]));
- }
- else if (argc>1&&strcmp(argv[1],"consumer")==0)
- {
- Consumer(atoi(argv[2]));
- }
- else
- {
- Parent();
- WaitForMultipleObjects(num,lpHandle,true,INFINITE);
- }
- return 0;
- }
linux代碼:
main.c文件
- #include <math.h>
- #include <stdio.h>
- #include <sys/time.h>
- #include <time.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/wait.h>
- #include <sys/sem.h>
- #include <stdlib.h>
- #define SHMKEY 75
- #define K 1024
- #define SEM_ID 225
- #define SEM_FULL 128
- #define SEM_EMPTY 256
- int shmid;
- int sem_set_id;
- int sem_full;
- int sem_empty;
- union semun
- {
- int val;
- struct semid_ds *buf;
- unsigned short int *array;
- struct seminfo *__buf;
- };
- struct buf
- {
- int num;
- int read;
- int write;
- int buffer[5];
- };
- void Producer()
- {
- int i;
- char argv[2];
- for (i = 0; i < 2; i++)
- {
- if (fork()==0)
- {
- argv[0]=i+48;
- argv[1]=0;
- //printf("%s\n",argv);
- execl("productor","productor",argv,(char*)0);
- exit(0);
- }
- }
- }
- void Consumer()
- {
- int i;
- char argv[2];
- for (i = 0; i < 3; i++)
- {
- if (fork()==0)
- {
- argv[0]=i+48;
- argv[1]=0;
- //printf("%s\n",argv);
- execl("consumer","consumer",argv,0);
- exit(0);
- }
- }
- }
- int main(int argc,int **argv)
- {
- int i,rc;
- struct buf *pint;
- char *addr;
- union semun sem_val;
- sem_set_id=semget(SEM_ID,1,IPC_CREAT|0600);
- sem_full=semget(SEM_FULL,3,IPC_CREAT|0600);
- sem_empty=semget(SEM_EMPTY,3,IPC_CREAT|0600);
- sem_val.val=1;
- rc=semctl(sem_set_id,0,SETVAL,sem_val);
- sem_val.val=3;
- rc=semctl(sem_empty,0,SETVAL,sem_val);
- sem_val.val=0;
- rc=semctl(sem_full,0,SETVAL,sem_val);
- shmid=shmget(SHMKEY,K,0777|IPC_CREAT);
- addr=shmat(shmid,0,0);
- pint=(struct buf *)addr;
- memset(addr,0,512);
- shmdt(addr);
- Producer();
- Consumer();
- printf("Create success!\n");
- return 0;
- }
consumer.c文件
- #include <math.h>
- #include <stdio.h>
- #include <sys/time.h>
- #include <time.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/wait.h>
- #include <sys/sem.h>
- #define SHMKEY 75
- #define K 1024
- #define SEM_ID 225
- #define SEM_FULL 128
- #define SEM_EMPTY 256
- int shmid;
- int sem_set_id;
- int sem_full;
- int sem_empty;
- union semun
- {
- int val;
- struct semid_ds *buf;
- unsigned short int *array;
- struct seminfo *__buf;
- };
- struct buf
- {
- int num;
- int read;
- int write;
- int buffer[5];
- };
- int main(int argc,char *argv[])
- {
- int i,j,r;
- struct buf *pint;
- char *addr;
- struct sembuf sem_op;
- int n;
- n=atoi(argv[1]);
- printf("success!\n");
- sem_set_id=semget(SEM_ID,1,0600);
- sem_full=semget(SEM_FULL,1,0600);
- sem_empty=semget(SEM_EMPTY,1,0600);
- for (i = 0; i < 4; i++)
- {
- sem_op.sem_num=0;
- sem_op.sem_op=-1;
- sem_op.sem_flg=0;
- semop(sem_full,&sem_op,1);
- srand((unsigned)time(0));
- do
- {
- r=rand()%5;
- }
- while(r==0);
- //printf("%d\n",rand()%5);
- sleep(r);
- sem_op.sem_num=0;
- sem_op.sem_op=-1;
- sem_op.sem_flg=0;
- semop(sem_set_id,&sem_op,1);
- time_t now;
- struct tm *timenow;
- time(&now);
- timenow=localtime(&now);
- shmid=shmget(SHMKEY,K,0777);
- if (shmid<0)
- {
- printf("shmget error\n");
- exit(-1);
- }
- addr=shmat(shmid,0,0);
- pint=(struct buf *)addr;
- pint->buffer[pint->read]=0;
- pint->read=(pint->read+1)%3;
- pint->num--;
- printf("%02d:%02d:%02d Consumer[%d]success %dleft ",timenow->tm_hour,timenow->tm_min,timenow->tm_sec,n,pint->num);
- for (j = 0; j < 3; j++)
- {
- printf("%d ",pint->buffer[j]);
- }
- printf("\n");
- shmdt(addr);
- sem_op.sem_num=0;
- sem_op.sem_op=1;
- sem_op.sem_flg=0;
- semop(sem_empty,&sem_op,1);
- sem_op.sem_num=0;
- sem_op.sem_op=1;
- sem_op.sem_flg=0;
- semop(sem_set_id,&sem_op,1);
- }
- printf("Consumer %d exit\n",n);
- return 0;
- }
productor.c
- #include <math.h>
- #include <stdio.h>
- #include <sys/time.h>
- #include <time.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/wait.h>
- #include <sys/sem.h>
- #define SHMKEY 75
- #define K 1024
- #define SEM_ID 225
- #define SEM_FULL 128
- #define SEM_EMPTY 256
- int shmid;
- int sem_set_id;
- int sem_full;
- int sem_empty;
- union semun
- {
- int val;
- struct semid_ds *buf;
- unsigned short int *array;
- struct seminfo *__buf;
- };
- struct buf
- {
- int num;
- int read;
- int write;
- int buffer[5];
- };
- int main(int argc,char *argv[])
- {
- int i,j,r;
- struct buf *pint;
- char *addr;
- struct sembuf sem_op;
- int n;
- n=atoi(argv[1]);
- printf("success!\n");
- sem_set_id=semget(SEM_ID,1,0600);
- sem_full=semget(SEM_FULL,1,0600);
- sem_empty=semget(SEM_EMPTY,1,0600);
- for (i = 0; i < 6; i++)
- {
- sem_op.sem_num=0;
- sem_op.sem_op=-1;
- sem_op.sem_flg=0;
- semop(sem_empty,&sem_op,1);
- srand((unsigned)time(0));
- do
- {
- r=rand()%5;
- }
- while(r==0);
- sleep(r);
- sem_op.sem_num=0;
- sem_op.sem_op=-1;
- sem_op.sem_flg=0;
- semop(sem_set_id,&sem_op,1);
- time_t now;
- struct tm *timenow;
- time(&now);
- timenow=localtime(&now);
- shmid=shmget(SHMKEY,K,0777);
- if (shmid<0)
- {
- printf("shmget error\n");
- exit(-1);
- }
- addr=shmat(shmid,0,0);
- pint=(struct buf *)addr;
- pint->buffer[pint->write]=1;
- pint->write=(pint->write+1)%3;
- pint->num++;
- printf("%02d:%02d:%02d Producer[%d]success %dleft ",timenow->tm_hour,timenow->tm_min,timenow->tm_sec,n,pint->num);
- for (j = 0; j < 3; j++)
- {
- printf("%d ",pint->buffer[j]);
- }
- printf("\n");
- shmdt(addr);
- sem_op.sem_num=0;
- sem_op.sem_op=1;
- sem_op.sem_flg=0;
- semop(sem_full,&sem_op,1);
- sem_op.sem_num=0;
- sem_op.sem_op=1;
- sem_op.sem_flg=0;
- semop(sem_set_id,&sem_op,1);
- }
- printf("Productor %d exit\n",n);
- return 0;
- }