1、1一、在 vc 里实现线程同步与互斥运行,你需要对一下几个函数进行研究学习与掌握使用:1、CreateThread() /创建线程的函数2、CreateSemaphore() /创建信号量的函数3、WaitForSingleObject() /4、ReleaseSemaphore() /*相关函数有:CreateProcess () /创建进程的函数Beginthread() /创建线程的函数OpenSemaphore()WaitForMultipleObjects()(有兴趣者可以对相关函数进行研究学习)2、第一步:你需要首先学会在 vc 里创建线程1、这里提供创建线程的函数是:Create
2、Thread()函数的原型是:HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,/ SDSIZE_TdwStackSize,/ initial stack sizeLPTHREAD_START_ROUTINE lpStartAddress,/ thread functionLPVOIDlpParameter,/ thread argumentDWORDdwCreationFlags,/ creation optionLPDWORDlpThreadId/ thread identifier);函数说明: 创建一个线程,线程指
3、定要执行的函数或者代码块。函数有六个参数,要理解六个参数分别是干什么用的。下面说明参数的使用:参数 1:lpThreadAttributes:指向 SECURITY_ATTRIBUTES 型态的结构的指针。在 Windows 98 中忽略该参数。在 Windows NT 中,NULL 使用默认安全性,不可以被子线程继承,否则需要定义一个结构体将它的 bInheritHandle 成员初始化为 TRUE,一般是 NULL。参数 2:dwStackSize,设置初始栈的大小,以字节为单位,如果为 0,那么默认将使用与调用该函数的线程相同的栈空间大小。任何情况下,Windows 根据需要动态延长堆栈
4、的大小。参数 3:lpStartAddress,指向线程函数的指针,即函数入口。形式: 函数名,函数名称没有限制,但是必须以下列形式声明:2DWORD WINAPI 函数名 (LPVOID lpParam) ,格式不正确将无法调用成功。比如一下程序 1 中的函数 fun1 可以这有定义:DWORD WINAPI Fun1(LPVOID IpParameter); /有点麻烦调用的时候是: hThread1 = CreateThread(NULL,0,Fun1,NULL,0,NULL);但是这有写函数有点不习惯,有点麻烦,所以可以这么来定义函数:void fun1();,但是调用的时候要这么写:
5、CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Fun1,NULL,0,NULL);/也就是 lpStartAddress 要这样通过 LPTHREAD_START_ROUTINE 转换。参数 4:lpParameter:向线程函数传递的参数,是一个指向结构的指针,不需传递参数时,为NULL。比如:你要向函数 fun1 传递一个字符串,可以这么来写程序:程序如下:#include #include #include #include#includevoid Fun1(LPVOID p);void main()HANDLE hThread1;char *a
6、=“hello fun1!“;hThread1 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Fun1,a,0,NULL);getch();CloseHandle(hThread1);void Fun1(LPVOID p)printf(“%sn“,(char *)p);向控制台打印:参数 5:dwCreationFlags :线程标志,可取值如下(1)CREATE_SUSPENDED(0x00000004):创建一个挂起的线程,注:传 0x00000004(2)0:表示创建后立即激活。(3)STACK_SIZE_PARAM_IS_A_RESERVA
7、TION(0x00010000):dwStackSize 参数指定初始的保留堆栈的大小,否则,dwStackSize 指定提交的大小。该标记值在 Windows 32000/NT and Windows Me/98/95 上不支持。参数 6:lpThreadId:保存新线程的 id。(各参数说明完毕,注:参数说明来自百度文档)函数返回值:函数成功,返回线程句柄;函数失败返回 false。若不想返回线程 ID,设置值为 NULL。到这你会在 vc 里面创建线程了吗?学习以上知识后,我们就会创建线程了,接下来我们要让线程同步与互斥执行。3、让线程同步与互斥执行为了能够会使用线程同步与互斥执行,我们
8、需要对一下函数进行研究学习。1、信号量的创建(基础是要了解什么是信号量以及信号量的控制)函数是:CreateSemaphore函数原型:HANDLECreateSemaphore(LPSECURITY_ATTRIBUTESlpSemaphoreAttributes,/ SDLONGlInitialCount,/ initial countLONGlMaximumCount,/ maximum countLPCTSTRlpName/ object name);参数说明如下:lpSemaphoreAttributes SECURITY_ATTRIBUTES,指定一个 SECURITY_ATTRIB
9、UTES 结构,或传递零值(将参数声明为 ByVal As Long,并传递零值)表示采用不允许继承的默认描述符。该参数定义了信号量的安全特性lInitialCount Long,设置信号量的初始计数。可设置零到 lMaximumCount 之间的一个值lMaximumCount Long,设置信号量的最大计数lpName String,指定信号量对象的名称。用 vbNullString 可创建一个未命名的信号量对象。如果已经存在拥有这个名字的一个信号量,就直接打开现成的信号量。这个名字可能不与一个现有的互斥体、事件、可等待计时器或文件映射的名称相符(注:来自百度文档)提供资料如下:2、信号量
10、(Semaphores )信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中的 PV 操作相同。它指出了同时访问共享资源的线程最大数目。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。在用 CreateSemaphore()创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的4访问,当前可用资源计数就会减1,只要当前可用资源计数是大于0 的,就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最
11、大数目,不能在允许其他线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过 ReleaseSemaphore()函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。PV 操作及信号量的概念都是由荷兰科学家 E.W.Dijkstra 提出的。信号量 S 是一个整数,S 大于等于零时代表可供并发进程使用的资源实体数,但 S 小于零时则表示正在等待使用共享资源的进程数。P 操作申请资源: (1)S 减1; (2)若 S 减1后仍大于等于零,则进程继续执行; (3)若 S 减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转入进程调
12、度。V 操作 释放资源: (1)S 加1; (2)若相加结果大于零,则进程继续执行; (3)若相加结果小于等于零,则从该信号的等待队列中唤醒一个等待进程,然后再返回原进程继续执行或转入进程调度。 信号量包含的几个操作原语: CreateSemaphore() 创建一个信号量 OpenSemaphore() 打开一个信号量 ReleaseSemaphore() 释放信号量 WaitForSingleObject() 等待信号量 (注:来自百度文档)知道什么是信号量了,怎么创建信号量了,那么接下来就学会如何控制信号量了3、信号量控制实现线程同步与互斥(相识 p、v 原语)学习研究函数:WaitFo
13、rSingleObject();ReleaseSemaphore();配合使用。 (这两函数由读者自己完成)提供的代码示例如下:程序 1 如下:#include #include #include #include#include#includeHANDLE s;5void Fun1();void Fun2();void main()HANDLE hThread1;HANDLE hThread2;s=CreateSemaphore(NULL,1,1,NULL);if(s)hThread1 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Fun1,NU
14、LL,0,NULL);hThread2 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Fun2,NULL,0,NULL);getch();CloseHandle(s);CloseHandle(hThread1);CloseHandle(hThread2);void Fun1()while(true)WaitForSingleObject(s,INFINITE);printf(“A“);Sleep(60000);ReleaseSemaphore(s,1,NULL);void Fun2()while(true)WaitForSingleObject(s,INFINITE);Sleep(2000);printf(“B“);ReleaseSemaphore(s,1,NULL);此程序有两线程,一个打印字符 A,一个打印字符 B,两线程同步互斥执行,当线程函数 fun1 先抢到资源,那么线程函数 fun2 就等待,实现了互斥访问资源,同时又同步执行。