一、实验目的
学习生产者与消费者的运行基本原理,学习使用共享内存区,学习使用多进程,学会使用锁互斥访问对象。
二、实验内容
一个大小为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;
- }
本文出自 “天才鸟蛋” 博客,请务必保留此出处http://curley.blog.51cto.com/1627940/816570