C实现
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include <process.h>
#define ID_M 0
#define ID_P_FROM 1
#define ID_P_TO 2
#define ID_C_FROM 3
#define ID_C_TO 5
#define PROCESS_NUM 5 //5个进程,2个生产者,3个消费者
#define WORKS_P 6
#define WORKS_C 4
#define LETTER_NUM 3 //缓冲区 ,大小为3
#define SHM_NAME "BUFFER"
//缓冲区结构(循环队列)
struct mybuffer
{
char letter[LETTER_NUM];
int head;
int tail;
int is_empty;
};
//共享主存区结构
struct sharemem
{
struct mybuffer data;
int index;
HANDLE semEmpty;
HANDLE semFull;
};
//文件映射对象句柄
static HANDLE hMapping;
//子进程句柄数组
static HANDLE hs[PROCESS_NUM + 1];
//得到5000以内的一个随机数
int get_random()
{
int t;
srand((unsigned)(GetCurrentProcessId() + time(NULL)));
t = rand() % 5000;
return t;
}
//得到A~Z的一个随机字母
char get_letter()
{
char a;
srand((unsigned)(getpid() + time(NULL)));
a = (char)((char)(rand() % 26) + 'A');
return a;
}
//进程克隆(通过参数传递进程的序列号)
void StartClone(int nCloneID)
{
char szFilename[MAX_PATH];
char szCmdLine[MAX_PATH];
STARTUPINFO si;
PROCESS_INFORMATION pi;
GetModuleFileName(NULL, szFilename, MAX_PATH);
sprintf(szCmdLine, "\"%s\" %d", szFilename, nCloneID);
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
//创建子进程
BOOL bCreateOK = CreateProcess(szFilename, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, & si, & pi);
hs[nCloneID] = pi.hProcess;
return;
}
//创建共享主存区
HANDLE MakeSharedFile()
{
//创建文件映射对象
HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(struct sharemem), SHM_NAME);
if (hMapping != INVALID_HANDLE_VALUE)
{
//在文件映射上创建视图
LPVOID pData = MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pData != NULL)
{
ZeroMemory(pData, sizeof(struct sharemem));
}
//关闭文件视图
UnmapViewOfFile(pData);
}
return (hMapping);
}
//主函数
int main(int argc, char *argv[])
{
int i, j, k;
int pindex = 1;
//下一个要创建的子进程的序列号
int nClone = ID_M;
//本进程序列号
char lt;
SYSTEMTIME systime;
//如果有参数,就作为子进程的序列号
if (argc > 1)
{
sscanf(argv[1], "%d", & nClone);
}
//对于所有进程
printf(" 当前进程ID: %d , 进程序号: %d\n", GetCurrentProcessId(), nClone);
//对于主控进程
if (nClone == ID_M)
{
printf("主进程启动成功\n");
//创建数据文件
hMapping = MakeSharedFile();
//映射视图
HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, SHM_NAME);
LPVOID pFile = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pFile != NULL)
{
struct sharemem *shm = (struct sharemem *)(pFile);
shm->data.head = 0;
shm->data.tail = 0;
shm->index = 0;
shm->semEmpty = CreateSemaphore(NULL, LETTER_NUM, LETTER_NUM, "SEM_EMPTY");
shm->semFull = CreateSemaphore(NULL, 0, LETTER_NUM, "SEM_FULL");
UnmapViewOfFile(pFile);
pFile = NULL;
}
else
{
printf("打开映射文件错误\n");
}
CloseHandle(hFileMapping);
//依次创建子进程
while (pindex <= PROCESS_NUM)
{
StartClone(pindex++);
}
//等待子进程完成
for (k = 1; k < PROCESS_NUM + 1; k++)
{
WaitForSingleObject(hs[k], INFINITE);
CloseHandle(hs[k]);
}
printf("主进程结束\n");
}
//对于生产者进程
else if (nClone >= ID_P_FROM && nClone <= ID_P_TO)
{
printf("生产者 %d 进程开始成功\n", nClone - ID_M);
//映射视图
HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, SHM_NAME);
LPVOID pFile = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pFile != NULL)
{
struct sharemem *shm = (struct sharemem *)(pFile);
shm->semEmpty = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "SEM_EMPTY");
shm->semFull = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "SEM_FULL");
for (i = 0; i < WORKS_P; i++)
{
WaitForSingleObject(shm->semEmpty, INFINITE);
Sleep(get_random());
shm->index++;
shm->data.letter[shm->data.tail] = lt = get_letter();
shm->data.tail = (shm->data.tail + 1) % LETTER_NUM;
shm->data.is_empty = 0;
GetLocalTime(&systime);
printf("[%02d]\t", shm->index);
printf("当前时间 %02d:%02d:%02d\t", systime.wHour, systime.wMinute, systime.wSecond);
printf("生产者 %d 放入 '%c'\t当前缓冲区:", nClone - ID_M, lt);
for (j = (shm->data.tail - 1 >= shm->data.head) ? (shm->data.tail - 1) : (shm->data.tail - 1 + LETTER_NUM); !(shm->data.is_empty) && j >= shm->data.head; j--)
{
printf("%c", shm->data.letter[j % LETTER_NUM]);
}
printf("\n");
ReleaseSemaphore(shm->semFull, 1, NULL);
}
UnmapViewOfFile(pFile);
pFile = NULL;
}
else
{
printf("打开映射文件错误\n");
}
CloseHandle(hFileMapping);
printf("生产者 %d 进程结束\n", nClone - ID_M);
}
//对于消费者进程
else if (nClone >= ID_C_FROM && nClone <= ID_C_TO)
{
printf("消费者 %d 进程开始成功\n", nClone - ID_P_TO);
//映射视图
HANDLE hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, SHM_NAME);
LPVOID pFile = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pFile != NULL)
{
struct sharemem *shm = (struct sharemem *)(pFile);
shm->semEmpty = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "SEM_EMPTY");
shm->semFull = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "SEM_FULL");
for (i = 0; i < WORKS_C; i++)
{
WaitForSingleObject(shm->semFull, INFINITE);
Sleep(get_random());
shm->index++;
lt = shm->data.letter[shm->data.head];
shm->data.head = (shm->data.head + 1) % LETTER_NUM;
shm->data.is_empty = (shm->data.head == shm->data.tail);
GetLocalTime(&systime);
printf("[%02d]\t", shm->index);
printf("当前时间 %02d:%02d:%02d\t", systime.wHour, systime.wMinute, systime.wSecond);
printf("消费者 %d 拿走 '%c'\t当前缓冲区:", nClone - ID_P_TO, lt);
for (j = (shm->data.tail - 1 >= shm->data.head) ? (shm->data.tail - 1) : (shm->data.tail - 1 + LETTER_NUM); !(shm->data.is_empty) && j >= shm->data.head; j--)
{
printf("%c", shm->data.letter[j % LETTER_NUM]);
}
printf("\n");
ReleaseSemaphore(shm->semEmpty, 1, NULL);
}
UnmapViewOfFile(pFile);
pFile = NULL;
}
else
{
printf("打开映射文件错误\n");
}
CloseHandle(hFileMapping);
printf("消费者 %d 进程结束\n", nClone - ID_P_TO);
}
CloseHandle(hMapping);
hMapping = INVALID_HANDLE_VALUE;
return 0;
}