16,472
社区成员
发帖
与我相关
我的任务
分享
/*---------------------------------------------------------------------------
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (C) 1999 - 2000 Microsoft Corporation. All rights reserved.
consumer.cpp
Contents:
The consumer process of the producer/consumer sample. This sample shows
how to use file mappings to implement a shared memory solution for the
bounded-buffer producer/consumer problem.
Usage:
To run this application, specify the shared memory name as a command-line
parameter as follows:
consumer memname
Design Notes:
This sample allows any number of producers and consumers to access a
single queue in shared memory.
The first producer creates the shared memory and sets up the queue. The
remaining producers and consumers open the memory and immediately start
using the existing queue.
When the queue is full, producers will block until the queue has an
open slot. When the queue is empty, consumers will block until the queue
has an item. In order to prevent the producers and consumers from blocking
forever, each waits with a timeout. If the timeout occurs, the producer
or consumer will check to see if the user wants to exit. If not, they
go back to waiting.
To determine if a user wants to exit, a console control handler looks
for a signal. If one occurs, it sets a flag that the producer/consumer
loop checks.
Since the queue is not mutually exclusive, the producers and consumers
share a single mutex to serialize access to the queue.
Notes:
See QUEUE.H for queue implementation details.
This sample will not compile for C; it requires C++ even though it does
not use classes.
---------------------------------------------------------------------------*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include "queue.h"
#include "common.h"
void ConsumeItem (int nItem);
BOOL WINAPI CtrlHandler (DWORD dwCtrlType);
bool g_fDone = false;
/*---------------------------------------------------------------------------
main (argc, argv)
Parameters
argc
Count of command-line arguments, including the name of the program.
argv
Array of pointers to strings that contain individual command-line
arguments.
Returns
SUCCESS if program executed successfully, FAILURE otherwise.
---------------------------------------------------------------------------*/
int main (int argc, char **argv)
{
int fResult = FAILURE;
HANDLE hMap = 0;
const char * pSharedMemName = 0;
QUEUE<int> * pQueue;
HANDLE hFullSem = 0,
hEmptySem = 0;
HANDLE hMutexLock = 0;
int item; /* used to hold data that's removed from queue */
/*
Validate command-line arguments. The last argument is the shared
memory name.
*/
if (argc != 2)
{
std::cerr << "usage: consumer <sharedmemname>\n";
return FAILURE;
}
pSharedMemName = argv[argc-1];
/*
Open shared memory and producer/consumer synchronization objects. If
can't, exit.
*/
hMap = OpenFileMapping (FILE_MAP_WRITE, 0, pSharedMemName);
if (!hMap)
goto DONE;
pQueue = (QUEUE<int> *)MapViewOfFile (hMap, FILE_MAP_WRITE, 0, 0, 0);
if (!pQueue)
goto DONE;
hFullSem = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE, FULL_SEM_NAME);
hEmptySem = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE, EMPTY_SEM_NAME);
hMutexLock = OpenMutex (MUTEX_ALL_ACCESS, FALSE, QUEUE_LOCK_NAME);
if (!hFullSem || !hEmptySem || !hMutexLock)
goto DONE;
/*
Remove items from the queue and consume them until the user says stop.
Use a console control handler to signal it's time to stop
*/
SetConsoleCtrlHandler (CtrlHandler, TRUE);
std::cerr << "Type Ctrl-C to exit\n";
while (!g_fDone)
{
// if queue is empty and we time out, see if we should exit.
if (WaitForSingleObject (hEmptySem, 1000) != WAIT_OBJECT_0)
continue;
WaitForSingleObject (hMutexLock, INFINITE);
if (!QueueRemoveItem (pQueue, &item))
std::cout << "couldn't remove item from queue!\n";
ReleaseMutex (hMutexLock);
ReleaseSemaphore (hFullSem, 1, 0); // signal producer that queue has empty slot.
ConsumeItem (item);
}
fResult = SUCCESS;
DONE:
/* Clean up all opened resources before exiting. */
if (!hFullSem)
CloseHandle (hFullSem);
if (!hEmptySem)
CloseHandle (hEmptySem);
if (!hMutexLock)
CloseHandle (hMutexLock);
if (pQueue)
UnmapViewOfFile (pQueue);
if (hMap)
CloseHandle (hMap);
if (fResult == FAILURE)
printf ("couldn't share memory named %s\n", pSharedMemName);
return (fResult);
}
/*---------------------------------------------------------------------------
ConsumeItem( nItem )
Consumes a single item by printing it to stdout.
Parameters
nItem
Item to be consumed.
---------------------------------------------------------------------------*/
void ConsumeItem (int nItem)
{
std::cout << nItem << "\n";
}
/*---------------------------------------------------------------------------
CtrlHandler( dwCtrlType )
Captures the console control signals such as Ctrl+C or Ctrl+Break sent by
the user. Then it signals the producer loop that the user would like to
exit.
Parameters
dwCtrlType
The console control signal that was generated.
Returns
Always returns true because it handles all console control signals.
---------------------------------------------------------------------------*/
BOOL WINAPI CtrlHandler (DWORD dwCtrlType)
{
/* For any event, signal producer loop that it's time to stop. */
g_fDone = true;
return TRUE;
}
/*---------------------------------------------------------------------------
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (C) 1999 - 2000 Microsoft Corporation. All rights reserved.
producer.cpp
Contents:
The producer process of the producer/consumer sample. This sample shows
how to use file mappings to implement a shared memory solution for the
bounded-buffer producer/consumer problem.
Usage:
To run this application, specify the shared memory name as a command-line
parameter as follows:
producer memname
Design Notes:
This sample allows any number of producers and consumers to access a
single queue in shared memory.
The first producer creates the shared memory and sets up the queue. The
remaining producers and consumers open the memory and immediately start
using the existing queue.
When the queue is full, producers will block until the queue has an
open slot. When the queue is empty, consumers will block until the queue
has an item. In order to prevent the producers and consumers from blocking
forever, each waits with a timeout. If the timeout occurs, the producer
or consumer will check to see if the user wants to exit. If not, they
go back to waiting.
To determine if a user wants to exit, a console control handler looks
for a signal. If one occurs, it sets a flag that the producer/consumer
loop checks.
Since the queue is not mutually exclusive, the producers and consumers
share a single mutex to serialize access to the queue.
Notes:
See QUEUE.H for queue implementation details.
This sample will not compile for C; it requires C++ even though it does
not use classes.
---------------------------------------------------------------------------*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include "queue.h"
#include "common.h"
const int MAX_QUEUE_ITEMS = 50;
int ProduceItem (void);
BOOL WINAPI CtrlHandler (DWORD dwCtrlType);
bool g_fDone = false;
/*---------------------------------------------------------------------------
main (argc, argv)
The main program that implements the producer process of the producer/consumer
sample.
Parameters
argc
Count of command-line arguments, including the name of the program.
argv
Array of pointers to strings that contain individual command-line
arguments.
Returns
SUCCESS if program executed successfully, FAILURE otherwise.
---------------------------------------------------------------------------*/
int main (int argc, char **argv)
{
int fResult = FAILURE;
DWORD dwMapResult;
HANDLE hMap = 0;
const char * pSharedMemName = 0;
QUEUE<int> * pQueue = 0;
HANDLE hFullSem = 0,
hEmptySem = 0;
HANDLE hMutexLock = 0;
int item; /* used to hold data that's put into the queue */
/*
Validate command-line arguments. The last argument is the shared
memory name.
*/
if (argc != 2)
{
std::cerr << "usage: producer <sharedmemname>\n";
return FAILURE;
}
pSharedMemName = argv[argc-1];
/*
If the shared memory is not already created, create it and set up the
queue. If the shared memory already exists, skip making the queue.
Then, create or open the synchronization objects associated with the
queue that are needed for an efficient solution to the producer/consumer
with bounded buffer problem. The initial state of producer/consumer
synchronization objects must be:
full semaphore count: N for an N-item queue
empty semaphore count: 0
lock mutex: unowned
*/
hMap = CreateFileMapping (INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0,
QueueComputeSize (pQueue, MAX_QUEUE_ITEMS),
pSharedMemName);
dwMapResult = GetLastError();
if (!hMap)
goto DONE;
pQueue = (QUEUE<int> *)MapViewOfFile (hMap, FILE_MAP_WRITE, 0, 0, 0);
if (!pQueue)
goto DONE;
if (dwMapResult != ERROR_ALREADY_EXISTS)
if (!QueueCreate (pQueue, MAX_QUEUE_ITEMS))
goto DONE;
hMutexLock = CreateMutex (NULL, FALSE, QUEUE_LOCK_NAME);
hFullSem = CreateSemaphore (NULL, pQueue->nMaxItems, pQueue->nMaxItems,
FULL_SEM_NAME);
hEmptySem = CreateSemaphore (NULL, 0, pQueue->nMaxItems, EMPTY_SEM_NAME);
if (!hFullSem || !hEmptySem || !hMutexLock)
goto DONE;
/*
Produce items and add them to the queue until the user says stop.
Use a console control handler to signal it's time to stop
*/
SetConsoleCtrlHandler (CtrlHandler, TRUE);
std::cerr << "Type Ctrl-C to exit\n";
item = ProduceItem();
while (!g_fDone)
{
// if queue is full and we time out, see if we should exit.
if (WaitForSingleObject (hFullSem, 1000) != WAIT_OBJECT_0)
continue;
WaitForSingleObject (hMutexLock, INFINITE);
QueueAddItem (pQueue, &item);
ReleaseMutex (hMutexLock);
ReleaseSemaphore (hEmptySem, 1, 0); // signal consumer--queue not empty
std::cout << item << "\n"; // print item just added but not inside lock
item = ProduceItem(); // make next item
}
fResult = SUCCESS;
DONE:
/* Clean up all opened resources before exiting. */
if (!hFullSem)
CloseHandle (hFullSem);
if (!hEmptySem)
CloseHandle (hEmptySem);
if (!hMutexLock)
CloseHandle (hMutexLock);
if (pQueue)
UnmapViewOfFile (pQueue);
if (hMap)
CloseHandle (hMap);
if (fResult == FAILURE)
std::cout << "couldn't share memory named " << pSharedMemName << "\n";
return (fResult);
}
/*---------------------------------------------------------------------------
ProduceItem( )
Produces a single item.
Returns
A new item.
---------------------------------------------------------------------------*/
int ProduceItem (void)
{
int item;
item = (int)GetCurrentProcessId();
return (item);
}
/*---------------------------------------------------------------------------
CtrlHandler( dwCtrlType )
Captures the console control signals such as Ctrl+C or Ctrl+Break sent by
the user. Then it signals the producer loop that the user would like to
exit.
Parameters
dwCtrlType
The console control signal that was generated.
Returns
Always returns true because it handles all console control signals.
---------------------------------------------------------------------------*/
BOOL WINAPI CtrlHandler (DWORD dwCtrlType)
{
/* For any event, signal producer loop that it's time to stop. */
g_fDone = true;
return TRUE;
}
/*-------------------------------------------------------------------------
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (C) 1999 - 2000 Microsoft Corporation. All rights reserved.
common.h
Purpose
Contains code that is common to both the producer and consumer.
Contents
Names of shared kernel objects:
FULL_SEM_NAME -- semaphore to make producers sleep when queue full
EMPTY_SEM_NAME -- semaphore to make consumers sleep when queue empty
QUEUE_LOCK_NAME -- mutex to enforce exclusive access to queue
Return values for main():
SUCCESS
FAILURE
-------------------------------------------------------------------------*/
#if !defined (INC_COMMON_H)
#define INC_COMMON_H
/* Names of kernel objects shared between producers and consumers */
#define FULL_SEM_NAME "PC_FULL_SEM"
#define EMPTY_SEM_NAME "EMPTY_FULL_SEM"
#define QUEUE_LOCK_NAME "PC_LOCK_MUTEX"
/* Return values for main() */
const int SUCCESS = 0;
const int FAILURE = 1;
#endif
Microsoft SDK\samples\winbase\SharedMem\Queue.h
/*---------------------------------------------------------------------------
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (C) 1999 - 2000 Microsoft Corporation. All rights reserved.
queue.h
The queue is a ring buffer of N items. The queue is a bounded size and cannot
grow.
Contents:
QueueCreate - Initializes a piece of memory into a queue
QueueComputeSize - Returns the size of the memory needed to hold a
queue of N items
QueueAddItem - Adds an item to the queue
QueueRemoveItem - Removes an item from the queue
Design notes:
This queue interface is templatized so that the queue can take a variety
of data types.
Queues can reside in shared memory so they can be shared between processes.
This implies they can be in multiple address spaces, and at a different base
address in each process. Therefore:
1) This implementation uses an array-based implementation instead of a
pointer implementation.
2) This implementation does not use C++ objects. The C++ compiler does
not guarantee that entire objects will be placed entirely within the
shared memory. Specifically, vtables will not be.
These queues are not reentrant and this implementation does not serialize
access because enforcing any locking behavior may result in unnecessary
overhead. (i.e. when the queue is not shared, then no locking is needed)
If these queues can be reentered (such as by multiple threads or processes),
the calling code must provide synchronization tailored to its needs.
Examples of such synchronization include mutexes, critical sections, or
spin locks.
---------------------------------------------------------------------------*/
#if !defined (INC_QUEUE_H)
#define INC_QUEUE_H
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
template<class T> struct QUEUE
{
int nNumItems; // 0
int nMaxItems; // N items
int in; // 0
int out; // 0
T data[1]; // first element of queue data, full size will be N items
};
/*----------------------------------------------------------------------------
QueueCreate( pQueueBase, nNumQueueItems )
Creates a queue than can hold nNumQueueItems at once. The caller must supply
the memory to hold the queue. It is advised that the caller first call
QueueComputeSize to determine how much memory will be needed by the queue.
Parameters
pQueueBase
A pointer to memory that will contain the new queue. This memory must
be allocated by the caller.
nNumQueueItems
The maximum number of items that can be in the queue at any one time.
Return Value
true if successfully created a queue, false if couldn't.
Notes
This queue can be in shared memory. It is not serialized so if multiple
threads or processes can use the queue simultaneously, they need to
synchronize access to the queue.
----------------------------------------------------------------------------*/
template<class T> bool QueueCreate (QUEUE<T> *pQueueBase, int nNumQueueItems)
{
bool fResult;
__try
{
pQueueBase->nNumItems = 0;
pQueueBase->nMaxItems = nNumQueueItems;
pQueueBase->in = 0;
pQueueBase->out = 0;
fResult = true;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
fResult = false;
}
return fResult;
}
/*----------------------------------------------------------------------------
QueueComputeSize( pQueue, nNumQueueItems )
Computes the size in bytes of a queue that can hold nNumQueueItems.
Parameters
pQueue
Pointer of the queue to compute the size of. Note that this pointer
is not dereferenced, and does not need to point to allocated memory.
It is used only to get the type (and therefore the size) of the items
that will be stored in the queue.
nNumQueueItems
Maximum number of items to put into the queue.
Return Value
The size in bytes of a queue that can hold nNumQueueItems.
----------------------------------------------------------------------------*/
template<class T> int QueueComputeSize (const QUEUE<T> *pQueue,
int nNumQueueItems)
{
return sizeof(QUEUE<T>) + ((nNumQueueItems-1) * sizeof(T));
}
/*----------------------------------------------------------------------------
QueueAddItem (pQueue, pItem )
Adds an item to the queue. If the queue is full, this function returns
immediately (no waiting) without adding the item.
Parameters
pQueue
Pointer to the queue to which the item should be added.
pItem
Pointer to the item to add to the queue.
Return Value
true if the item added to the queue, false if not.
----------------------------------------------------------------------------*/
template<class T> bool QueueAddItem (QUEUE<T> *pQueue, const T * pItem)
{
// If the queue is full, return.
if (pQueue->nNumItems == pQueue->nMaxItems)
return false;
/*
Insert item, then advance in pointer to next empty slot, then update
number of items in the queue.
*/
pQueue->data[pQueue->in] = *pItem;
pQueue->in = (pQueue->in +1) % pQueue->nMaxItems;
++pQueue->nNumItems;
return true;
}
/*----------------------------------------------------------------------------
QueueRemoveItem( pQueue, pItem )
Removes an item from a queue. If the queue is empty, this function returns
immediately.
Parameters
pQueue
Pointer to the queue from which the item should be removed.
pItem
Pointer to memory that will receive the item removed from the queue.
Return Value
true if the item added to the queue, false if not.
----------------------------------------------------------------------------*/
template<class T> bool QueueRemoveItem (QUEUE<T> * pQueue, T * pItem)
{
// if queue empty, return
if (pQueue->nNumItems == 0)
return false;
// remove item, then advance out pointer to next item to remove
*pItem = pQueue->data[pQueue->out];
pQueue->out = (pQueue->out + 1) % pQueue->nMaxItems;
--pQueue->nNumItems;
return true;
}
#endif
// 创建文件句柄
HANDLE hFile = ::CreateFile(lpszFileName, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// 创建文件映射
HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READONLY | SEC_COMMIT, NULL, NULL, NULL);
// 读取映射中的内存
LPVOID lpBuffer = ::MapViewOfFile(hMap, FILE_MAP_READ, NULL, NULL, NULL);
// 好了文件的内存已经获取了,你可以随意处理了
// 释放映射内存
::UnmapViewOfFile(lpBuffer);
// 关闭文件映射
::CloseHandle(hMap);
// close file handle
::CloseHandle(hFile);
?