大连东软信息学院-多核多线程-实验一.doc_第1页
大连东软信息学院-多核多线程-实验一.doc_第2页
大连东软信息学院-多核多线程-实验一.doc_第3页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

项目一 :Windows*Threads多线程编程模块一:基础模块4 编译执行, 输出结果: 简答与思考:1 写出修改后的HelloThreads的代码。/ HelloThreads.cpp : 定义?控?制?台应|用?程序的?入?口点?。#include stdafx.h#include const int numThreads = 4;DWORD WINAPI helloFunc(LPVOID arg) int myNum=*(int*)arg); printf(Hello Thread!Thread %d n,myNum); return 0; int main(int argc,_TCHAR* argv)HANDLE hThreadnumThreads; int tNumnumThreads;for (int i = 0; i numThreads; i+) tNumi=i; hThreadi = CreateThread(NULL, 0, helloFunc, &tNumi, 0, NULL ); WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);return 0; 2 项目总结。在主线程中循环调用CreateThread()函数生成四个子线程分别去执行helloFunc()函数,并将线程的句柄保存在hThread数组中,CreateThread()的第四个参数给每个线程传递参数tNum获取该线程号,由helloFunc()的参数接收并指向内容。由于主线程为每个子线程传递了不同的参数,所以通过子线程的执行结果可以判断出四个线程的执行顺序。这个实验要我们初步认识了程序的并行化设计思想,为以后的并行化程序设计打下了基础。3 模块二:临界区模块3 编译执行,记录结果:Pi = The time of calculation was seconds6 编译执行,记录结果:Pi = The time of calculation was seconds7 加速比:1.90503951 , 并行效率: 0.47625988 简答与思考:1 如何进行并行化的?请写出并行化的思路与具体的代码。 答:在程序中创建两个子线程,另主线程等待所有的子线程执行结束后退出。代码:#include stdafx.h#include #include static long num_steps=1000000000; const int gNumThreads=2;double step=0.0,pi=0.0,sum=0.0;CRITICAL_SECTION gCS;DWORD WINAPI threadFunction(LPVOID pArg)int myNum=*(int *)pArg);double sum1=0.0,x;for (int i=myNum; i num_steps; i+=gNumThreads) x = (i+0.5)*step; sum1 = sum1 + 4.0/(1.0 + x*x); EnterCriticalSection(&gCS); sum+=sum1; LeaveCriticalSection(&gCS); return 0;int main(int argc,_TCHAR* argv) clock_t start, stop; start = clock(); HANDLE threadHandlesgNumThreads; int tNumgNumThreads; InitializeCriticalSection(&gCS); step = 1.0/(double) num_steps; for(int i=0;igNumThreads;+i) tNumi=i; threadHandlesi=CreateThread(NULL,0,threadFunction,&tNumi,0,NULL); WaitForMultipleObjects(gNumThreads,threadHandles,TRUE,INFINITE); DeleteCriticalSection(&gCS); pi = step * sum; stop = clock(); printf(Pi = %12.12fn,pi); printf(The time of calculation was %f secondsn,(double)(stop - start)/1000.0); return 0;4 在本模块中,哪些变量是需要保护的?为什么?采取什么方法实现的?答:1)临界资源是需要保护的,也就是sum变量,这里将对sum的更新操作定义为临界区操作2)在多线程程序中,对于在子线程执行的代码中出现的被更新的全局变量要多加考虑,因为具有这种特点的变量,很有可能会引起数据冲突,如果处理不好会使程序产生功能性错误3)EnterCriticalSection(&gCS); sum+=sum1;LeaveCriticalSection(&gCS); 在创建子线程前调用InitializeCriticalSection(&gCS);函数对临界区进行初始化,然后调用EnterCriticalSection(&gCS);函数获取临界区的访问权,访问结束后调用LeaveCriticalSection(&gCS);函数释放临界区的访问权,在退出程序前需要调用DeleteCriticalSection(&gCS);函数注销临界区,释放临界区资源。3是否可以对该并行化方案进行进一步的优化?如何优化? 答:可以。更改创建线程的数目,分别计算出加速比和效率,比较结果进行取舍。4 项目总结。在使用临界区时,可以根据需要,在程序中定义多个临界区对象,用来对不同的代码段进行互斥访问,这样做的好处是可以增加程序的并行度。总之,在设计多线程程序时,应该为每一个需要互斥的共享资源定义一个临界区变量。模块三:事件模块3 编译执行,记录结果:Result is The time of calculation was seconds4 阅读代码,回答下面问题。(1)主线程共创建 5 个子线程。(2)各子线程调用的函数各是什么? DWORDWINAPIthreadProc(LPVOIDpar) DWORDWINAPImasterThreadProc(LPVOIDpar) (3)主线程等待 4 个子线程的执行结束。6 改进后的,编译执行,记录结果:Result is The time of calculation was seconds简答与思考:1 在WINAPI threadProc(LPVOID par)函数中为什么用临界区互斥了线程对threadCount的访问?为什么对于全局数据变量sums的访问没有互斥? WINAPI threadProc(LPVOID par)函数使用多线程执行的threadCount是记录线程个数的,而它对于masterThreadProc()函数要等待所有线程(threadCount)做完对sums的计算,然后再进行最后的四个线程结构的累加,它是这两个函数的共享变量,对于它的操作必须原子化,以保证每次只有一个线程对其自增,所以使用临界区互斥了每个线程对threadCount的访问,避免了数据冲突的发生。 而对于数据变量sums每一个数组元素下标值是每个子线程获得的参数,该参数标记了各个子线程,sums数组分别对应每一个线程,从而使每个子线程操作的变量分别保存在对应的数组元素中,四个线程互不影响,所以并不需要互斥。2 简述源代码中存在的问题,详述提出的改进方案及相关代码。 源代码中为使“master”子线程等待其余四个子线程执行完毕,使用空循环保持“master”子线程的“等待”状态,这显然不是好的方法;改进方案中使用了事件,事件用于线程间的执行顺序以保证对共享资源操作的完整性,本程序中,“master”子线程是另外创建的,它需要另外四个子线程的执行结果,所以需要等待以保证获得它们的结果后再进行操作,使用事件机制,程序中定义四个未激发的人工重置事件,“master”子进程在执行时以wait方式等待事件被激发,由于其余四个子线程在完成任务后将事件从未激发设置为激发态,从而使“master”子线程继续执行余下操作#include stdafx.h#include #include #include #include#define NUMTHREADS 4#define SERIES_MEMBER_COUNT 100000HANDLE *threadHandles, masterThreadHandle,*eventHandles;CRITICAL_SECTION countCS;double *sums;double x = 1.0, res = 0.0;int threadCount = 0;double getMember(int n, double x)double numerator = 1;for( int i=0; in; i+ )numerator = numerator*x;if ( n % 2 = 0 )return ( - numerator / n );elsereturn numerator/n;DWORD WINAPI threadProc(LPVOID par)int threadIndex = *(int *)par);sumsthreadIndex = 0;for(int i=threadIndex; iSERIES_MEMBER_COUNT;i+=NUMTHREADS)sumsthreadIndex += getMember(i+1, x);SetEvent(eventHandlesthreadIndex);/Signal Master thread that one more processing thread is done/EnterCriticalSection(&countCS); /threadCount+; /LeaveCriticalSection(&countCS);delete par;return 0;DWORD WINAPI masterThreadProc(LPVOID par)for( int i=0; iNUMTHREADS; i+ ) ResumeThread(threadHandlesi); / Start computing threads/while (threadCount != NUMTHREADS) / busy wait until all threads are done with computation of partial sumsWaitForMultipleObjects(NUMTHREADS,eventHandles,TRUE,INFINITE);res = 0;for(int i=0; iNUMTHREADS; i+)res += sumsi;return 0;int main() clock_t start,stop;threadHandles = new HANDLENUMTHREADS + 1;eventHandles = new HANDLENUMTHREADS +1 ;/InitializeCriticalSection(&countCS);sums = new doubleNUMTHREADS; start=clock();for(int i=0; iNUMTHREADS;i+)int * threadIdPtr = new int;*threadIdPtr = i;threadHandlesi = CreateThread(NULL, 0, threadProc, threadIdPtr, CREATE_SUSPENDED, NULL);eventHandlesi=CreateEvent(NULL,TRUE,FALSE,NULL);threadHandlesNUMTHREADS = CreateThread(NULL, 0, masterThreadProc, NULL, 0, NULL);printf(Count of ln(1 + x) Mercators series members is %dn,SERIES_MEMBER_COUNT);printf(Argument value of x is %fn, (double)x);WaitForMultipleObjects(NUMTHREADS+1,threadHandles,TRUE,INFINITE);stop=clock();for(int i=0; iNUMTHREADS+1; i+ ) CloseHandle(threadHandlesi);delete threadHandles;delete eventHandles;/DeleteCriticalSection(&countCS);delete sums;printf(Result is %10.8fn, res);printf(By function call ln(1 + %f) = %10.8fn,x, log(1+x);printf(The time of calculation was %f secondsn,(double)(stop-start)/1000.0);printf(Press any key . );getch();return 0;3是否可以对该并行化方案进行进一步的优化?如何优化? 线程在被创建时就执行,不再去唤醒,“master”只需等待事件被激发,效率就会有所提高。4 项目总结。 模块四:信号量模块3 这是串行代码实现,编译执行,记录结果。6 编译执行并行版本,多次运行,记录结果: 第1次执行结果:第2次执行结果:第3次执行结果:10 修正后项目的输出结果为:简答与思考:1 SemaphoreS项目与SemaphoreT项目执行结果不一致的原因是什么? 在多线程中fd和TotalWords,TotalEventWords,TotalOddWords属于共享变量,在并发执行的过程中会造成数据冲突。fd对于每个线程是互斥的,是因为在文件指针往下一行改变时,不准许其它线程对该操作有影响,不然就会造成该问题的计数结果不正确的现象;而TotalWords,TotalEventWords,TotalOddWords这几个变量,是计算总的字符串个数,含有偶数数量字符的字符串的个数及含有奇数个字符的字符串的个数,毋庸置疑,它们也是共享资源,在对他们进行累加时,要注意数据冲突。2 如何修改SemaphoreT项目源代码?写出修改思路和关键代码。可以采用临界区的方法去做,也可以采用信号量。信号量也是一种内核对象,它可以对当前的资源计数,这是与临界区最大的不同,当资源数量大于0时,等待该信号量的线程就可以获得该资源得以继续执行。改进方案:在代码中应用两个信号量hSem1,hSem2,hSem1用于线程对文件指针fd的互斥,hSem2用于对全局变量TotalWords,TotalEventWords,TotalOddWords的互斥,对于每一个子线程,由于我们的思路是按行计算,然后累加的,对于偶数数量字符的字符串的个数以及含有奇数数量字符串的个数计算,要注意采取巧妙点的处理办法。#include stdafx.h#include #include #include FILE *fd; int TotalEvenWords = 0, TotalOddWords = 0, TotalWords = 0;HANDLE hSem1,hSem2;const int NUMTHREADS = 4;int GetNextLine(FILE *f, char *Line) if (fgets(Line, 132, f)=NULL) if (feof(f)return EOF; else return 1;int GetWordAndLetterCount(char *Line)int Word_Count = 0,OddWords=0,EvenWords=0, Letter_Count = 0;for (int i=0;i132;i+)if (Linei!= )&(Linei!=0)&(Linei!=n) Letter_Count+; else if(Letter_Count!=0) if (Letter_Count % 2) OddWords+; Word_Count+;Letter_Count = 0; else EvenWords+; Word_Count+; Letter_Count = 0; if (Linei=0) break;return (Word_Count*10000+OddWords*100+EvenWords); DWORD WINAPI CountWords(LPVOID arg) BOOL bDone = FALSE ; char inLine132; int lCount=0;while (!bDone) WaitForSingleObject(hSem1,INFINITE);/进? bDone = (GetNextLine(fd, inLine) = EOF); ReleaseSemaphore(hSem1,1,NULL);/出? if (!bDone) lCount=GetWor

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论