四个线程写四个文件02 Semaphore = Event * 4

但是我有一个担心,当举旗时,4个线程至少有一个线程不在等待该旗子时【因为线程调度不可预知】,这样某个线程在某次命令中会不会多跑一圈?而那个掉队的线程就跑不了,导致死锁。

试验:把threadfunc改成下面的代码,即让SetEvent和 WaitForSingleObject有个不确定的间隔。跑了七八下, 结果都正确。但是再跑一下,死锁真的发生了。所以这个现象是比较难以重复的。

UINT WINAPI WriteNumberIntoFile(PVOID pParam){
	//由于创建线程是要一定的开销的,所以新线程并不能第一时间执行到这来    
    int iNumber = *(int*)pParam+1;
    SetEvent(hEventPtrParam);//触发事件  
	int iFileId = (iNumber+3)%iThreads;
	while(iCurrTimes < iMaxTimes){
		//通知主线程准备就绪
		SetEvent(hEvents[iNumber-1]);
		 Sleep(rand()%100);
		//等待主线程允许写
		WaitForSingleObject(hSemaphore, INFINITE);
		//如果条件不满足,不进行写操作,直接跳出循环
		if(iCurrTimes >= iMaxTimes)			break;
		ofs[iFileId] << iNumber << " ";
		iFileId = (iFileId+3)%iThreads;
	}
	cout << "ChildThread[" << iNumber << "] Exits" << endl;
	return 0;
}
第三次尝试:
把Semaphore改成4个自动重置事件(Event)。打个比方,四个车道,每个车道一个车(线程),每个车道有自己的红绿灯(自动重置事件),灯变绿,车子跑起来,并且灯立即变红。这样不会出现某个车跑2圈,而另外的某车跑不了的情况。
尝试也成功了。但我认为这个可靠多了。缺点是多用了一些同步对象。但正确性总是第一位的。

#include <Windows.h>
#include <shlwapi.h> 
#include <strsafe.h>
#include<cstdlib>
#include<ctime>
#include<string>
#include<iostream>
#include <fstream>
#include <process.h>
using namespace std;

#pragma comment(lib,"Shlwapi.lib")


const int iThreads = 4;//线程个数
//HANDLE hSemaphoreNotifyChilds;//主线程通知子线程的“交通信号灯”
HANDLE hEventNotifyChilds[iThreads];//主线程通知子线程开始写 
HANDLE hEventPtrParam;//用于主线程和子线程之间的同步(传递i的值)
HANDLE hEventNotifyMain[iThreads] = {0};//自动置位事件,用于子线程通知主线程
ofstream ofs[iThreads];//四个输出文件流

int iMaxTimes = 10;//最大输出次数
int iCurrTimes = 0;//当前输出次数

UINT WINAPI WriteNumberIntoFile(PVOID pParam){
	//由于创建线程是要一定的开销的,所以新线程并不能第一时间执行到这来    
	int iNumber = *(int*)pParam+1;
	SetEvent(hEventPtrParam);//触发事件  
	int iFileId = (iNumber+3)%iThreads;
	while(iCurrTimes < iMaxTimes){
		//通知主线程准备就绪
		SetEvent(hEventNotifyMain[iNumber-1]);
		Sleep(rand()%100);//【因为线程调度不可预知】
		//等待主线程允许写
		//WaitForSingleObject(hSemaphoreNotifyChilds, INFINITE);
		WaitForSingleObject(hEventNotifyChilds[iNumber-1], INFINITE);
		//如果条件不满足,不进行写操作,直接跳出循环
		if(iCurrTimes >= iMaxTimes)			break;
		ofs[iFileId] << iNumber << " ";
		iFileId = (iFileId+3)%iThreads;
	}
	cout << "ChildThread[" << iNumber << "] Exits" << endl;
	return 0;
}

void main()
{
	TCHAR szExe[MAX_PATH]; memset(szExe, 0, sizeof(TCHAR)*MAX_PATH);
	GetModuleFileName(NULL, szExe, MAX_PATH);

	TCHAR szCurrWorkPath[MAX_PATH]; memset(szCurrWorkPath, 0, sizeof(TCHAR)*MAX_PATH);
	GetCurrentDirectory(MAX_PATH, szCurrWorkPath);


	TCHAR szFile[MAX_PATH]; TCHAR szSpar[] = TEXT("\\");
	const TCHAR* szFiles[iThreads] = {TEXT("A.txt"), TEXT("B.txt"), TEXT("C.txt"), TEXT("D.txt")};
	for(int i = 0; i < iThreads; i++){//如果当前文件存在,则删除;
		memset(szFile, 0, sizeof(TCHAR)*MAX_PATH);
		StringCchCopy(szFile, lstrlen(szCurrWorkPath)+1, szCurrWorkPath); //D:/Projects/BoostPro/BoostPro
		StringCchCat(szFile, lstrlen(szFile)+lstrlen(szSpar)+1, szSpar);//D:/Projects/BoostPro/BoostPro/
		StringCchCat(szFile, lstrlen(szFile)+lstrlen(szSpar)+lstrlen(szFiles[i])+1, szFiles[i]);//D:/Projects/BoostPro/BoostPro/X.txt
		if(PathFileExists(szFile) && !DeleteFile(szFile))		MessageBox(NULL, szFile, TEXT("Msg"), MB_OK);
	}


	srand((unsigned)time(NULL));//设置随机数的种子


	//hSemaphoreNotifyChilds = CreateSemaphore(NULL, 0, iThreads, NULL);
	//初始化事件 自动置位,初始无触发
	hEventPtrParam = CreateEventW(NULL, FALSE, FALSE, NULL); 
	HANDLE hThreads[iThreads]; memset(hThreads, 0, sizeof(HANDLE)*4);
	for(int i = 0; i < iThreads; i++){//等子线程接收到参数时主线程可能改变了这个i的值 
		//创建事件,自动置位,初始复位
		hEventNotifyChilds[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
		hEventNotifyMain[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
		//打开文件
		ofs[i].open(szFiles[i], ios_base::trunc);	
		//创建线程
		unsigned uThreadId;
		hThreads[i] = (HANDLE)_beginthreadex(NULL, 0, &WriteNumberIntoFile, (LPVOID)(&i), 0, &uThreadId);
		WaitForSingleObject(hEventPtrParam, INFINITE);//等待事件被触发,等待到复位后,立马置位
	}

	for(; iCurrTimes < iMaxTimes; ++iCurrTimes){
		cout << "Main thread is waiting..." << endl;
		//等待就绪子线程的通知
		WaitForMultipleObjects(iThreads, hEventNotifyMain, TRUE, INFINITE);
		//通知就绪子线程进行写操作
		//ReleaseSemaphore(hSemaphoreNotifyChilds, iThreads, NULL);
		for(int i = 0; i < iThreads; i++)			SetEvent(hEventNotifyChilds[i]);
		cout << "iCurrTimes = " << iCurrTimes << endl;
	}
	//保证子线程已全部运行结束  
	cout << "WaitFor ChildThreads, iCurrTimes = " << iCurrTimes << endl;
	//主线程将iCurrTimes+1变为10之前,子线程可能已经陷入了等待
	//ReleaseSemaphore(hSemaphoreNotifyChilds, iThreads, NULL);
	for(int i = 0; i < iThreads; i++)			SetEvent(hEventNotifyChilds[i]);
	WaitForMultipleObjects(iThreads, hThreads, TRUE, INFINITE);  

	//CloseHandle(hSemaphoreNotifyChilds);
	for(int i = 0; i < iThreads; i++){
		//销毁事件
		CloseHandle(hEventNotifyChilds[i]);
		CloseHandle(hEventNotifyMain[i]);
		//关闭线程句柄
		CloseHandle(hThreads[i]);
		//关闭文件
		ofs[i].close();
	}
}



猜你喜欢

转载自blog.csdn.net/knightonhourse/article/details/80265667
今日推荐