进程与线程同步以及进程间共享数据的方法,大家讨论一下

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都将结束运行。
当然,为了缩小实例的长度和降低复杂性,所有针对文件的操作都是模拟的。


********

上面小弟为别人的书写的一个示例,演示进程、线程同步以及数据共享的。大家讨论讨论,是否有不适当的地方。
...全文
143 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
ajiva 2002-03-17
  • 打赏
  • 举报
回复
ff
cmpp 2001-12-17
  • 打赏
  • 举报
回复
我来学习一下!
lownr 2001-10-26
  • 打赏
  • 举报
回复
对了,有空到小弟的主页看看。

http://www.dualface.com

如果打不开请刷新一下,263免费主页啦,没办法。
lownr 2001-10-26
  • 打赏
  • 举报
回复
好像不给分大家都不看啊?
lownr 2001-10-26
  • 打赏
  • 举报
回复
我自己up一下。

1,649

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 非技术类
社区管理员
  • 非技术类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧