线程学习总结-----/*自己编写*/

来源:互联网 发布:网络扁平化的优点 编辑:程序博客网 时间:2024/06/01 20:50

一、 WaitForSingleObject()函数



二、 _beginthreadex()和CreatThread()区别

       使用标准C运行库函数是,尽量使用_beginthreadex()函数。

       参考:http://blog.csdn.net/morewindows/article/details/7421759


三、 Interlocked系列函数

        多线程环境下对一个全局变量进行读写时,对这个变量的操作必须是原子操作,即一个线程对其进行访问修改时,其它线程要等这个线程操作完毕后才能进行修改。对变量进行原子操作可使用interlocked系列函数,包括自增、自减、赋值等操作。

        参考:http://blog.csdn.net/morewindows/article/details/7429155


四、同步与互斥:

        同步:主线程等待子线程某个操作完成后再启动下一个动作,这就涉及到线程间的同步;

        互斥:子线程之间会互斥的改动和输出全局变量,而要求全局变量规律的改变,这就涉及到线程间的互斥。

        参考:http://blog.csdn.net/morewindows/article/details/7442639

                   http://blog.csdn.net/morewindows/article/details/7445233

        

        解决互斥可以使用interlocked系列函数、也可以使用关键段。

        但这两个都解决不了同步问题,同步可以通过事件来完成。

        如果线程间的互斥只涉及到一个全局变量,可以通过Interlocked系列函数来解决;如果线程间的互斥是一段操作,则需要使用关键段来解决。

        例:参考中的经典多线程例子里,线程函数如下:

//子线程函数  unsigned int __stdcall Fun(void *pPM)  {  int nThreadNum = *(int *)pPM;  SetEvent(g_hThreadEvent);Sleep(50);//some work should to do  EnterCriticalSection(&g_csThreadCode);//进入各子线程互斥区域  g_nNum++;  Sleep(0);//some work should to do  printf("线程编号为%d  全局资源值为%d\n", nThreadNum, g_nNum);  LeaveCriticalSection(&g_csThreadCode);//离开各子线程互斥区域   return 0;  } 

主函数如下:

// MulThread.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <stdio.h>#include <Windows.h>#include <process.h>long g_nNum; //全局资源  unsigned int __stdcall Fun(void *pPM); //线程函数  const int THREAD_NUM = 10; //子线程个数  //关键段变量声明  CRITICAL_SECTION  g_csThreadCode;  HANDLE  g_hThreadEvent; int _tmain(int argc, _TCHAR* argv[]){printf("     经典线程同步 关键段\n");  printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");  //关键段初始化  InitializeCriticalSection(&g_csThreadCode);  g_hThreadEvent = CreateEvent(NULL,FALSE,FALSE,NULL);HANDLE  handle[THREAD_NUM];   g_nNum = 0;   int i = 0;  while (i < THREAD_NUM)   {  handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL); WaitForSingleObject(g_hThreadEvent,INFINITE);i++;  }  WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);  DeleteCriticalSection(&g_csThreadCode); CloseHandle(g_hThreadEvent);system("pause");return 0;}


如果,不需要输出printf这句,直接用interlocked函数InterlockedIncrement((LPLONG)&g_nNum),代替g_nNum++即可解决互斥问题。但要求是要有输出这句,printf语句中因又用到了g_nNum这个全局变量,所以如果只是用Interlocked函数,

//子线程函数  unsigned int __stdcall Fun(void *pPM)  {  int nThreadNum = *(int *)pPM;  SetEvent(g_hThreadEvent);Sleep(50);//some work should to do  //EnterCriticalSection(&g_csThreadCode);//进入各子线程互斥区域  //g_nNum++;  InterlockedIncrement((LPLONG)&g_nNum);Sleep(0);//some work should to do  printf("线程编号为%d  全局资源值为%d\n", nThreadNum, g_nNum);  //LeaveCriticalSection(&g_csThreadCode);//离开各子线程互斥区域   return 0;  }

输出结果如下:

可以看到,全局变量的输出值并没有依次递增,这是因为printf这句并不是紧接在InterlockedIncrement((LPLONG)&g_nNum)后执行,比如线程3执行完InterlockedIncrement((LPLONG)&g_nNum)后,还没执行后面的printf,线程5开始调用Fun,进入到printf这句,此时的g_nNum仍存在互斥。

为解决此问题,应用关键段,将有互斥的语句全包含进来,这样可以解决互斥问题。

如下:

EnterCriticalSection(&g_csThreadCode);//进入各子线程互斥区域  g_nNum++;  Sleep(0);//some work should to do  printf("线程编号为%d  全局资源值为%d\n", nThreadNum, g_nNum);  LeaveCriticalSection(&g_csThreadCode);//离开各子线程互斥区域 
线程函数按上述修改后,输出如下:



总结:

单个全局变量的互斥可使用Interlocked系列函数完成原子操作,一段互斥的操作可使用关键段;

关键段是有“线程所有权”概念的;

关键段可以用于线程间的互斥,但不可以用于同步;

事件可以解决线程间同步问题,因此也能解决互斥问题

五、 互斥量

        互斥量是内核对象,它与关键段都有“线程所有权”所以不能用于线程的同步。

         互斥量能够用于多个进程之间线程互斥问题,并且能完美的解决某进程意外终止所造成的“遗弃”问题。

        参考:http://blog.csdn.net/morewindows/article/details/7470936




0 0
原创粉丝点击