Windows系統——多進程多線程任務隊列管理(進程通信)(臨界資源訪問)
相關知識
Windows系統——進程通信共享內存區
Windows系統——進程創建
Windows系統——多線程互斥訪問臨界資源
Windows系統——線程創建
實現代碼
- Printer.cpp
/*
author : eclipse
email : [email protected]
time : Sun Apr 26 12:44:13 2020
*/
#include <bits/stdc++.h>
#include <windows.h>
#include "Queue.cpp"
using namespace std;
//queue<string> q;
Queue q;
const int BUFFER_SIZE = 1024;
const char shareMemory[] = "task";
CRITICAL_SECTION mutex;
char *buffer = NULL;
DWORD CALLBACK read(LPVOID param) {
while (true) {
if (buffer[0]) {
EnterCriticalSection(&mutex);
string t = string(buffer);
q.push(t);
LeaveCriticalSection(&mutex);
if (!strcmp(buffer, "finish")) {
break;
}
buffer[0] = '\0';
}
}
return 0;
}
int main(int argc, char const *argv[])
{
InitializeCriticalSection(&mutex);
HANDLE mappingFileHandle;
if (!(mappingFileHandle = CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
BUFFER_SIZE,
shareMemory))) {
printf("Create file mapping error(%d)!", GetLastError());
abort();
}
if (!(buffer = (char *)MapViewOfFile(
mappingFileHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
BUFFER_SIZE))) {
printf("Map file error(%d)", GetLastError());
abort();
}
HANDLE readThreadHandle = NULL;
DWORD readThreadId;
if (!(readThreadHandle = CreateThread(NULL, 0, read, NULL, 0, &readThreadId))) {
printf("Thread create error(%d)\n", GetLastError());
abort();
}
while (q.empty() || q.front() != "finish") {
if (!q.empty() && q.front() != "finish") {
printf("Received data\n");
printf("Ready to print\n");
printf("Printing [");
for (int i = 0; i < 10; i++) {
Sleep(200);
printf("=");
}
printf("]\n");
EnterCriticalSection(&mutex);
cout << q.front() << endl;
q.pop();
LeaveCriticalSection(&mutex);
printf("\07Print successfully\n");
}
}
DeleteCriticalSection(&mutex);
UnmapViewOfFile(buffer);
CloseHandle(mappingFileHandle);
return 0;
}
- Writer.cpp
/*
author : eclipse
email : [email protected]
time : Sun Apr 26 12:44:13 2020
*/
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
const int BUFFER_SIZE = 1024;
const char shareMemory[] = "task";
int main(int argc, char const *argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess(NULL,
(LPSTR) "printer.exe",
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi)) {
printf("Create Process error(%d)!\n", GetLastError());
abort();
}
HANDLE mappingFileHandle;
if (!(mappingFileHandle = CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
BUFFER_SIZE,
shareMemory))) {
printf("Create file mapping error(%d)!", GetLastError());
abort();
}
char *buffer = NULL;
if (!(buffer = (char*) MapViewOfFile(
mappingFileHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
BUFFER_SIZE
))) {
printf("Map file error(%d)\n", GetLastError());
abort();
}
while (strcmp(buffer, "finish")) {
printf("Send data\n");
gets(buffer);
}
UnmapViewOfFile(buffer);
CloseHandle(mappingFileHandle);
return 0;
}
- Queue.cpp
/*
author : eclipse
email : [email protected]
time : Sun Apr 26 14:46:53 2020
*/
#include<bits/stdc++.h>
using namespace std;
typedef string ElemType;
const int MAXSIZE = 1000;
struct Queue
{
ElemType data[MAXSIZE];
int frontPointer;
int rearPointer;
bool tag;
ElemType front();
void pop();
void push(ElemType x);
bool empty();
bool full();
Queue() : frontPointer(0), rearPointer(0), tag(false) {}
};
ElemType Queue::front() {
return empty() ? "-1" : data[frontPointer];
}
void Queue::pop() {
if (empty()) {
printf("The queue is empty!\n");
return;
}
frontPointer = (frontPointer + 1) % MAXSIZE;
if (frontPointer == rearPointer) {
tag = false;
}
}
void Queue::push(ElemType x) {
if (full()) {
printf("The queue is full!\n");
return;
}
data[rearPointer] = x;
rearPointer = (rearPointer + 1) % MAXSIZE;
if (rearPointer == frontPointer) {
tag = true;
}
}
bool Queue::empty() {
return frontPointer == rearPointer && !tag;
}
bool Queue::full() {
return frontPointer == rearPointer && tag;
}
實現
- 效果
從Writer進程輸入數據,Writer進程創建子進程Printer,子進程主線程創建子線程從內存區讀取數據進入等待隊列,子進程Printer主線程從隊列取隊首元素異步地輸出數據(間隔兩秒打印一次數據) - 思路
上述實現借用兩個進程,父進程輸入,子進程藉助兩個線程,一個線程讀取共享內存區的數據,主線程每個兩秒相對於子線程異步地打印數據, 上述實現中的隊列是自行編寫的,將Queue q;
改成queue<string> q;
即可使用STL隊列 - 互斥訪問隊列
子進程Printer主線程和子線程互斥地進入臨界區訪問共享全局變量隊列q,子線程等待輸入,主線程打印結果 - 進程通信共享內存區
進程Writer和子進程Printer通過共享內存區進行進程間通信,父進程輸入數據進入共享內存區,子進程子線程從共享內存區讀取數據,父進程輸出數據到控制檯
編譯過程
g++ Printer.cpp -o printer
g++ Writer.cpp -o writer
writer.exe
效果截圖
最後
- 由於博主水平有限,不免有疏漏之處,歡迎讀者隨時批評指正,以免造成不必要的誤解