进程与线程同步以及进程间共享数据的方法,大家讨论一下
lownr 2001-10-26 07:47:02 下面的是源代码:
**** DataAnalyzer.h ****
class DataAnalyzer
{
public:
int Run();
private:
void AnalyzingData();
static DWORD WINAPI AnalyzingThread(LPVOID lpParameter);
static DWORD WINAPI ManagerThread(LPVOID lpParameter);
static char* datafilepath; // 数据输入文件名
static const int maxthread; // 最大线程数
static HANDLE m_hEvent;
typedef struct
{
HANDLE hEvent; // 线程对应的事件句柄
int number; // 数据
}threaddata;
};
**** DataAnalyzer.cpp ****
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
using namespace std;
#include "dataanalyzer.h"
char* DataAnalyzer::datafilepath = NULL;
const int DataAnalyzer::maxthread = 5; // 最大线程数
HANDLE DataAnalyzer::m_hEvent = NULL;
int DataAnalyzer::Run()
{
MSG msg;
// 打开事件句柄
m_hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, "syn_event");
if(m_hEvent == NULL)
{
cout << "没有找到需要的事件。\n"
<< "DataAnalyzer只能够由DataMaker调用,请勿直接使用.\n";
cout << "按 ENTER 键退出.....";
cin.get();
return -1;
}
cout << "DataAnalyzer 正在启动....";
Sleep(1000);
cout << "OK\n\n\n";
// 设置事件为有信号,使得正在等待的 DataMaker 可以继续运行
SetEvent(m_hEvent);
while(GetMessage(&msg, NULL, NULL, NULL))
{
switch(msg.message)
{
case WM_NOTIFY: // DataMaker 数据包写入完毕后收到这个消息
if(msg.wParam == 1)
{
cout << "#### 收到 DataMaker 发送的通知,可以获取数据文件名了.\n";
HANDLE hfilemap = OpenFileMapping(FILE_MAP_READ, FALSE, "demo_filemapping");
LPVOID lpview = MapViewOfFile(hfilemap, FILE_MAP_READ, 0, 0, 0);
cout << "hfilemap = " << hex << hfilemap << ", lpview = " << lpview << endl;
int nlen = *((int*)lpview);
datafilepath = new char[nlen];
memcpy(datafilepath, (BYTE*)lpview + 4, nlen);
UnmapViewOfFile(lpview);
CloseHandle(hfilemap);
cout << "datafilepath : " << datafilepath << endl << endl;
// 将事件变为有信号,以此通知 DataMaker 已经准备好了。
SetEvent(m_hEvent);
}
else
{
cout << "#### 收到 DataMaker 发送的消息,数据已经写入完毕.\n";
AnalyzingData();
}
break;
case WM_CLOSE: // 任务完成时收到这个消息
cout << "\n\n\n#### 收到 DataMaker 发送的消息,可以退出运行了.\n";
delete datafilepath;
PostQuitMessage(0);
break;
}
}
// 让事件变为有信号,通知 DataMaker, DataAnalyzer进程即将结束
SetEvent(m_hEvent);
CloseHandle(m_hEvent);
cout << "按 ENTER 键关闭窗口.";
cin.get();
return 0;
}
void DataAnalyzer::AnalyzingData()
{
cout << "#### 建立管理者线程.\n";
DWORD dwThreadID;
HANDLE hManagerThread = CreateThread(NULL, 0,
ManagerThread, 0, CREATE_SUSPENDED,
&dwThreadID);
cout << "#### 等待管理者线程结束.\n";
ResumeThread(hManagerThread);
WaitForSingleObject(hManagerThread, INFINITE);
CloseHandle(hManagerThread);
// 让事件变为有信号,通知 DataMaker 分析工作已经结束
cout << "#### 分析工作已经全部完成.\n\n\n";
SetEvent(m_hEvent);
}
DWORD DataAnalyzer::ManagerThread(LPVOID lpParameter)
{
HANDLE* hThreads = new HANDLE[maxthread]; // 保存句柄
HANDLE* hEvents = new HANDLE[maxthread]; // 保存事件
threaddata* tds = new threaddata[maxthread]; // 线程需要的数据
cout << "@@@@ 管理线程开始.\n";
// 建立事件
for(int i = 0; i < maxthread; i++)
{
hEvents[i] = CreateEvent(NULL, FALSE, TRUE, NULL);
}
DWORD dwThreadID;
SYSTEMTIME stime;
GetSystemTime(&stime);
for(int nCount = 0; nCount < stime.wMilliseconds % 10 + 1; nCount++)
{
// 等待一个分析线程结束
i = WaitForMultipleObjects(maxthread, hEvents, FALSE, INFINITE) - WAIT_OBJECT_0;
// 关闭句柄
CloseHandle(hThreads[i]);
// 为分析线程准备数据
Sleep(350);
tds[i].hEvent = hEvents[i];
// 模拟读入的数据
tds[i].number = 0;
// 建立分析线程但不立刻启动
hThreads[i] = CreateThread(NULL, 0,
AnalyzingThread, (LPVOID)&tds[i],
0,
&dwThreadID);
}
// 等待所有的分析线程结束
for(i = 0; i < maxthread; i++)
{
WaitForSingleObject(hThreads[i], INFINITE);
CloseHandle(hEvents[i]);
}
delete hThreads;
delete hEvents;
delete tds;
cout << "@@@@ 管理线程结束.\n";
return 0;
}
DWORD DataAnalyzer::AnalyzingThread(LPVOID lpParameter)
{
threaddata* ptd = (threaddata*)lpParameter;
DWORD dwid = GetCurrentThreadId();
cout << "!!!! " << hex << dwid << " 分析线程开始. START\n";
// 模拟数据分析过程
Sleep(ptd->number);
// 将事件设置为有信号后,前面 ManagerThread 中的
// i = WaitForMultipleObjects(maxthread, hEvents, FALSE, INFINITE) - WAIT_OBJECT_0
// 将返回一个已经空闲的句柄的索引
SetEvent(ptd->hEvent);
cout << "!!!! " << hex << dwid << " 分析线程结束. END\n";
return 0;
}
int main(int argc, char* argv[])
{
DataAnalyzer theObj;
return theObj.Run();
}
**** DataMaker.h ****
class DataMaker
{
public:
int Run();
private:
void MakeData(); // 准备数据包
void SaveData(); // 写入数据包
void StartDataAnalyzer(); // 启动 DataAnalyzer
DWORD m_idDataAnalyzer; // DataAnalyzer 的线程ID
HANDLE m_hEvent;
static const char* const datafilepath; // 数据文件
};
**** DataMaker.cpp ****
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
using namespace std;
#include "datamaker.h"
const char* const DataMaker::datafilepath = "c:\\datafile.txt";
void DataMaker::StartDataAnalyzer()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
// 建立事件
m_hEvent = CreateEvent(NULL, TRUE, FALSE, "syn_event");
// 建立进程 DataAnalyzer
if(CreateProcess(TEXT("DataAnalyzer.exe"),
NULL,
NULL,
NULL,
FALSE,
CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi) == FALSE)
{
cout << GetLastError() << endl;
throw 0; // 如果建立进程失败抛出异常
}
cout << "等待 DataAnalyzer 做好准备.....";
WaitForSingleObject(m_hEvent, INFINITE);
cout << "OK\n";
CloseHandle(pi.hProcess);
m_idDataAnalyzer = pi.dwThreadId; // 得到 DataAnalyzer 的线程ID
}
void DataMaker::MakeData()
{
cout << "DataMaker 正在准备数据....";
SYSTEMTIME stime;
GetSystemTime(&stime);
Sleep(stime.wMilliseconds % 3000);
cout << "OK\n";
}
void DataMaker::SaveData()
{
// 模拟写数据
cout << "正在写入数据....";
SYSTEMTIME stime;
GetSystemTime(&stime);
Sleep(stime.wMilliseconds % 1000);
cout << "OK\n";
}
int DataMaker::Run()
{
cout << "DataMaker 开始运行.\n";
// 启动 DataAnalyzer
try
{
StartDataAnalyzer();
}
catch(...)
{
cout << "启动 DataAnalyzer 失败.\n";
return -1;
}
cout << "建立页面文件文件映射来和 DataAnalyzer 共享数据.\n";
HANDLE hfilemap = CreateFileMapping((HANDLE)0xfffffffff,
NULL,
PAGE_READWRITE,
0,
lstrlen(datafilepath) + 5,
"demo_filemapping");
LPVOID lpview = MapViewOfFile(hfilemap,
FILE_MAP_READ | FILE_MAP_WRITE,
0, 0, 0);
cout << "hfilemap = " << hex << hfilemap << ", lpview = " << lpview << endl;
*((int*)lpview) = lstrlen(datafilepath) + 1;
memcpy((BYTE*)lpview + 4, datafilepath, lstrlen(datafilepath) + 1);
UnmapViewOfFile(lpview);
cout << "通知 DataAnalyzer 接收数据文件名, ";
ResetEvent(m_hEvent);
PostThreadMessage(m_idDataAnalyzer, WM_NOTIFY, (WPARAM)1, NULL);
cout << "并等待其完成处理.....";
WaitForSingleObject(m_hEvent, INFINITE);
cout << "OK\n";
CloseHandle(hfilemap);
for(int nCount = 0; nCount < 10; nCount++)
{
cout << "\n\n*****************************\n\n"
<< "进行第 " << dec << nCount + 1 << " 次数据数据准备工作.\n";
// 准备数据包
MakeData();
// 等待事件变为有信号
// DataAnalyzer 会在数据处理完毕后将事件变为有信号
cout << "等待 DataAnalyzer 的分析工作完成.....";
WaitForSingleObject(m_hEvent, INFINITE);
cout << "OK\n";
// 保存数据包
SaveData();
// 通知 DataAnalyzer 数据包已经写入完毕
cout << "通知 DataAnalyzer 新的数据包已经写入到文件中了.\n";
ResetEvent(m_hEvent);
PostThreadMessage(m_idDataAnalyzer, WM_NOTIFY, NULL, NULL);
}
cout << "\n\n没有数据需要分析了,"
<< "等待 DataAnalyzer 完成分析任务....";
// 等待 DataAnalyzer 完成任务
WaitForSingleObject(m_hEvent, INFINITE);
cout << "OK\n";
// 通知 DataAnalyzer 任务完成,可以退出了
cout << "OK,大家可以休息了.\n";
PostThreadMessage(m_idDataAnalyzer, WM_CLOSE, NULL, NULL);
// 释放事件
CloseHandle(m_hEvent);
cout << "DataMaker 运行结束.\n按 ENTER 键关闭窗口.";
cin.get();
return 0;
}
int main(int argc, char* argv[])
{
DataMaker theObj;
return theObj.Run();
}
**** 说明 ****
实例包含两个文件DataMaker.exe和DataAnalyzer.exe,都是控制台程序。
我们启动程序DataMaker后,DataMaker会自动的创建一个新进程DataAnalyzer。之后DataMaker开始准备一系列由不同种类的数据组成的数据包,准备完成后,DataMaker打开一个文件,将这个数据包添加到文件中。添加完成后,DataMaker将通知DataAnalyzer新的数据包已经添加完毕,然后接着继续准备新的数据包。
而同一时刻,DataAnalyzer一直在等待DataMaker添加完数据包后发送的通知。在收到通知后,DataAnalyzer会打开文件开始处理数据包,并且创建一些线程来分析数据,但同一时刻运行的线程数量不能超过上限。DataAnalyzer在分析工作完毕后会通知DataMaker。而DataMaker在没有收到DataAnalyzer发送的处理完毕通知前不会再次向文件中添加新的数据包。
在这个过程进行10次后,DataMaker将通知DataAnalyzer工作已经结束,可以退出了。然后DataMaker和DataAnalyzer都将结束运行。
当然,为了缩小实例的长度和降低复杂性,所有针对文件的操作都是模拟的。
********
上面小弟为别人的书写的一个示例,演示进程、线程同步以及数据共享的。大家讨论讨论,是否有不适当的地方。