操作系统课,进程间通信,一小段代码求答疑

Lukas88 2017-10-31 09:00:50
因为课上正在讲操作系统的进程间通信,所以用共享内存机制做了这道题,但是出现了一些奇怪的问题,排除了很多错误原因,还是不知道错在哪里,放在这里,请大家提提意见~

操作系统:利用进程的共享内存机制进行多进程/线程快速排序的问题。
全代码分为五部分:随机数文件的生成,快速排序中队列的分割(只找出每一次分割的位置),冒泡排序(对1000个一下的随机数使用的排序算法),线程函数,主函数。
在命令窗口中输入“input.txt”

随机数文件生成,分割函数,冒泡排序函数应该没有问题,但是每次排序都不彻底,可以从最终的input.txt文件中看出排序的痕迹,但是没有完全按照从小到大排列,而且还出现了几个数连在一起的问题(因为那个数看起来很长),我最开始以为是各个进程对共享内存区的写入出现了冲突,所以用互斥量mutex1做了写保护,但是问题依然存在,对代码再三更改,思考了很久,也不知道错在哪里,恳请各位高手帮小妹一把,多谢了~


//共享内存机制
#include<iostream>
#include<windows.h>
#include<fstream>
#include<time.h>
#include<queue>
#include<TCHAR.h>
using namespace std;
#define semaphore int
#define N 1000000

int n = 1;
int* DB;
int SortedNum = 0;
bool END = false; //标识排序工作的完成
TCHAR filename[256];
HANDLE mutex1 = CreateMutex(NULL, FALSE, NULL);
HANDLE finished = CreateSemaphore(NULL, 0, 1, NULL);

void CreateRandNum() {
FILE *file = fopen("input.txt", "w+");//读写打开一个文本文件
srand((unsigned int)time(NULL));
int* data = (int*)malloc(sizeof(int)*N);
for (int i = 0; i < N; i++) {
data[i] = rand();
fprintf(file, "%d ", data[i]);
}
fclose(file);
}

class Param {
public:
int f; //front
int t; //tail
Param(int a, int b) {
f = a;
t = b;
}
};

//对包含元素大于1000的序列进行再分割,快速排序
int Partition(int *p, int left, int right) {
cout << n++ << endl;
int f = left;
int t = right;
int key = *(p + f);
while (f < t) {
while (f < t &&key <= *(p + t)) t--;
p[f] = p[t];
while (f < t && key >= *(p + f)) f++;
p[t] = p[f];
}
p[f] = key;
return f;
}

//对包含元素小于1000的序列不再分割,进行冒泡排序,其实也可以递归调用快速排序,只不过不再创建新的进程
void Sort(int*p, int f, int t) {
int num = t - f + 1;
for (int i = 0; i < num - 1; i++)
for (int j = 0; j < num - 1 - i; j++) {
if (*(p + j + 1) < *(p + j)) {
int temp = *(p + j);
*(p + j) = *(p + j + 1);
*(p + j + 1) = temp;
}
}
}

/*快速排序线程*/
DWORD WINAPI QuickSortThread(PVOID pM) {
Param *pBuf = (Param*)pM;
while (!END) {
if (pBuf->t - pBuf->f < 1000) {
WaitForSingleObject(mutex1, INFINITE);
Sort(DB, pBuf->f, pBuf->t);
SortedNum += pBuf->t - pBuf->f + 1;
ReleaseMutex(mutex1);
if (SortedNum == N)
ReleaseSemaphore(finished, 1, NULL);
}
else {
WaitForSingleObject(mutex1, INFINITE);
int s = Partition(DB, pBuf->f, pBuf->t);
SortedNum++;
ReleaseMutex(mutex1);
Param *para1 = new Param(pBuf->f, s - 1);
Param *para2 = new Param(s + 1, pBuf->t);
HANDLE Thread1 = CreateThread(NULL, 0, QuickSortThread, para1, 0, NULL);
WaitForSingleObject(Thread1, INFINITE);
CloseHandle(Thread1);
HANDLE Thread2 = CreateThread(NULL, 0, QuickSortThread, para2, 0, NULL);
WaitForSingleObject(Thread2, INFINITE);
CloseHandle(Thread2);
}
}
return 0;
}

int main() {
CreateRandNum();
printf("输入生成文件名:\n");
scanf("%ws", filename);

//Create file mapping
HANDLE hFile = CreateFile(filename, (GENERIC_READ | GENERIC_WRITE),
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
//if (hFile == INVALID_HANDLE_VALUE) printf("Can't open file!");
HANDLE MapSrc = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, _T("input_map"));
DB = (int*)MapViewOfFile(MapSrc, FILE_MAP_ALL_ACCESS, 0, 0, 0);

Param *p = new Param(0, N - 1);
HANDLE Thread = CreateThread(NULL, 0, QuickSortThread, p, 0, NULL);

WaitForSingleObject(finished, INFINITE);
FlushViewOfFile(DB, 4 * N);

CloseHandle(hFile);
CloseHandle(MapSrc);
CloseHandle(Thread);
return 0;
}
...全文
475 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
Lukas88 2017-11-02
  • 打赏
  • 举报
回复
真的感谢您,这么用心!我觉得说的正是我出现的问题,不过我只能明天再调试了。再次感谢!!
Hello Worm 2017-11-01
  • 打赏
  • 举报
回复
附上我有改动的几个函数,整个程序还没调通哦


void CreateRandNum() {
	FILE *file = fopen("input.txt", "w+");//读写打开一个文本文件
	srand((unsigned int)time(NULL));
	int* data = (int*)malloc(sizeof(int)*N);
	for (int i = 0; i < N; i++) {
		data[i] = rand();
		//fprintf(file, "%d ", data[i]);
		fwrite(&data[i], 4, 1, file);  //assume int takes 4Bytes
	}
	fclose(file);
}

//对包含元素大于1000的序列进行再分割,快速排序
int Partition(int *p, int left, int  right) {
	cout << n++ << endl;
	int f = left;
	int t = right;
	int key = p[f];    //the way "p+f" is not correct, "f" here is the index but not offset
	while (f < t) {
		while (f < t &&key <= p[t]) t--;
		p[f] = p[t];
		while (f < t && key >= p[f]) f++;
		p[t] = p[f];
	}
	p[f] = key;
	return f;
}

//对包含元素小于1000的序列不再分割,进行冒泡排序,其实也可以递归调用快速排序,只不过不再创建新的进程
void Sort(int*p, int f, int t) {
	int num = t - f + 1;
	for (int i = 0; i < num - 1; i++)
		for (int j = 0; j < num - 1 - i; j++) {
			if (p[ j + 1] < p[j]) {
				int temp = p[j];
				p[j] = p[j+1];
				p[j+1] = p[j];
			}
		}
}
Hello Worm 2017-11-01
  • 打赏
  • 举报
回复
难道看到女码农,还研究这么深奥的问题,一定要支持一下。 你的这段代码我有跑了一下,思路上挺正确的,还有些不太合理的地方需要你首先调整: 1. 你的文件input.txt是以文本方式存储的,但在文件共享时,是以二进制方式处理的,所以实际存储和处理的根本不是同一堆数。举个例子,随机数"3045",你用notepad打开看到的当然是3045,但通过程序中的DB指针,你看到的将是0x33 0x30 0x34 0x35,所以当你通过类似int key = *(p + f);操作时,你得到的key值并不是3045,而是0x33303435(假定你不懂大小端),这个值也就是你指出的“几个数连在一起的问题“。所以,如果你要用大量的指针操作,建议你以二进制方式存储。 2.你的QuickSortThread线程是一个递归线程,所以必须有合理的退出机制,否则大量占用系统资源,而且使得逻辑混乱,难以厘清。在我看来你的,第一个条件:冒泡排序的部分,在排完序就就完成了使命了,应该马上退出while循环,结束该线程的使命。 另外,建议你一开始把你的N弄的小一点,等执行顺利后再整大一点,如果我的理解没有错的话,按照你目前的设定,这个程序至少需要创建1000000/1000 = 1000个线程,这已经远超常规程序开发的线程数了,事实上试验阶段,5个左右的线程足以说明问题,而且还能让你深入了解线程间的可能产生的问题。直接上几千个线程,就算十几年的工程师也未必能理出头绪的。
Hello Worm 2017-11-01
  • 打赏
  • 举报
回复
这是可以工作的源码,你的代码还有些其他小问题。这个input.txt需要用二进制方式打开,例如notepad++的Hex插件
//共享内存机制
#include<iostream>
#include<windows.h>
#include<fstream>
#include<time.h>
#include<queue>
#include<TCHAR.h>
using namespace std;
#define semaphore int
#define N 100000

int n = 1;
int* DB;
int SortedNum = 0;
bool END = false;  //标识排序工作的完成
TCHAR filename[256];
HANDLE mutex1 = CreateMutex(NULL, FALSE, NULL);
HANDLE finished = CreateSemaphore(NULL, 0, 1, NULL);

void CreateRandNum() {
	FILE *file = fopen("input.txt", "wb+");//读写打开一个文本文件
	srand((unsigned int)time(NULL));
	int* data = (int*)malloc(sizeof(int)*N);
	for (int i = 0; i < N; i++) {
		data[i] = rand();
		//fprintf(file, "%d ", data[i]);
		fwrite(&data[i], 4, 1, file);
	}
	fclose(file);
}

class Param {
public:
	int f;  //front
	int t;  //tail
	Param(int a, int b) {
		f = a;
		t = b;
	}
};

//对包含元素大于1000的序列进行再分割,快速排序
int Partition(int *p, int left, int  right) {
	cout << n++ << endl;
	int f = left;
	int t = right;
	int key = p[f];
	while (f < t) {
		while (f < t &&key <= p[t]) t--;
		p[f] = p[t];
		while (f < t && key >= p[f]) f++;
		p[t] = p[f];
	}
	p[f] = key;
	return f;
}

//对包含元素小于1000的序列不再分割,进行冒泡排序,其实也可以递归调用快速排序,只不过不再创建新的进程
void Sort(int*p, int f, int t) {
	int num = t - f + 1;
	for (int i = 0; i < num-1; i++)
		for (int j = 0; j < num-1 -i; j++) {
			if (p[f+j + 1] < p[f+j]) {
				int temp = p[f+j];
				p[f+j] = p[f+j + 1];
				p[f+j + 1] = temp;
			}
		}
}

/*快速排序线程*/
DWORD WINAPI QuickSortThread(PVOID pM) {
	Param *pBuf = (Param*)pM;
	while (!END) {
		if (pBuf->t - pBuf->f < 1000) {
			WaitForSingleObject(mutex1, INFINITE);
			Sort(DB, pBuf->f, pBuf->t);
			SortedNum += pBuf->t - pBuf->f + 1;
			ReleaseMutex(mutex1);
			if (SortedNum >= N)
				ReleaseSemaphore(finished, 1, NULL);
		}
		else {
			WaitForSingleObject(mutex1, INFINITE);
			int s = Partition(DB, pBuf->f, pBuf->t);
			SortedNum++;
			ReleaseMutex(mutex1);
			if (pBuf->f != s) {
				Param *para1 = new Param(pBuf->f, s - 1);
				HANDLE Thread1 = CreateThread(NULL, 0, QuickSortThread, para1, 0, NULL);
				WaitForSingleObject(Thread1, INFINITE);
				CloseHandle(Thread1);
			}
			if (s != pBuf->t) {
				Param *para2 = new Param(s + 1, pBuf->t);
				HANDLE Thread2 = CreateThread(NULL, 0, QuickSortThread, para2, 0, NULL);
				WaitForSingleObject(Thread2, INFINITE);
				CloseHandle(Thread2);
			}
		}
		break;	//Well, actuall we don't need while loop as we will "wait" until the recursive thread been finished.
	}
	return 0;
}

int main() {
	CreateRandNum();
	printf("输入生成文件名:\n");
	scanf("%ws", filename);

	//Create file mapping
	HANDLE hFile = CreateFile(filename, (GENERIC_READ | GENERIC_WRITE),
		FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	//if (hFile == INVALID_HANDLE_VALUE) printf("Can't open file!");
	HANDLE MapSrc = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, _T("input_map"));
	DB = (int*)MapViewOfFile(MapSrc, FILE_MAP_ALL_ACCESS, 0, 0, 0);

	Param *p = new Param(0, N - 1);
	HANDLE Thread = CreateThread(NULL, 0, QuickSortThread, p, 0, NULL);

	WaitForSingleObject(finished, INFINITE);
	FlushViewOfFile(DB, 4 * N);

	CloseHandle(hFile);
	CloseHandle(MapSrc);
	CloseHandle(Thread);
	return 0;
}
Lukas88 2017-10-31
  • 打赏
  • 举报
回复
还有一个问题,就是排序结果只有在逐行调试(尤其是将端点设在排序函数之内)才能在input.txt,也就是最终的文件中看到,如果直接运行就看不到排序痕迹,这个时候排序进程到底运行了吗,为什么直接运行就没有调试时能看到的结果 呢?非常疑惑,求解。

4,436

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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