多线程的学习2

来源:互联网 发布:php找工作怎么样 编辑:程序博客网 时间:2024/06/09 14:10
继续了解多线程,多线程的通信方式我感觉主要就是全局变量,而且这个使用起来感觉也最方便,也许我的理解可能有误。

多线程的通信方式:

1、全局变量

全局变量在使用时通常会加上volatile声明(防止编译器对此变量进行优化),还有在使用中如果需要对这个全局变量进行操作,最好加上互斥量

2、message消息机制

常用的message通信的接口主要有:PostMessage和PostThreadMessage,前者是和向主窗口发送消息,后者是任意两个线程之间的通信接口。

PostMessage函数原型:B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam); 参数:    hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:    HWND.BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口 和弹出式窗口。消息不被寄送到子窗口。    NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。    Msg:指定被寄送的消息。    wParam:指定附加的消息特定的信息。    IParam:指定附加的消息特定的信息。    返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。MS还提供了SendMessage方法进行消息间通讯,SendMessage(),他和PostMessage的区别是:SendMessage是同步的,而PostMessage是异步的。SendMessage必须等发送的消息执行之后,才返回。
PostThreadMessage函数原型:BOOL PostThreadMessage(DWORD idThread,UINT Msg,WPARAM wParam, LPARAM lParam);参数除了ThreadId之外,基本和PostMessage相同。目标线程通过GetMessage()方法来接受消息。注:使用这个方法时,目标线程必须已经有自己的消息队列。否则会返回ERROR_INVALID_THREAD_ID错误。可以用PeekMessage()给线程创建消息队列。PostThreadMessage可以用于线程之间的异步通讯,因为它不用等待调用者返回,这也许是线程通讯中最简单的一种方法了。但是要注意以下问题。1 .PostThreadMessage有时会失败,报1444错误(Invalid thread identifier. )其实这不一定是线程不存在的原因,也有可能是线程不存在消息队列(message queue)造成的。事实上,并不是每个thread都有message queue,那如何让thread具有呢?答案是,至少调用message相关的function一次,比如GetMessage,PeekMessage。2.如果是post动态分配的memory给另外一个thread,要注意内存的正确释放。3.PostThreadMessage不能够post WM_COPYDATE之类的同步消息,否则会报错4.最好不要使用PostThreadMessage post message给一个窗口,使用PostMessage替代。

3、CEvent对象

CEvent为MFC中的一个对象,可以通过对CEvent的触发状态进行改变,从而实现线程间的通信和同步,这个主要是实现线程直接同步的一种方法。

线程之间的同步

线程之间的同步有多种方式:临界区(CCriticalSection)、事件(CEvent)、互斥量(CMutex)、信号量(CSemaphore),这些同步方式使得各个线程可以协调工作,程序运行起来更安全。

1、临界区
临界区是保证在某一个时间只有一个线程可以访问数据的方法。
临界区对应一个CcriticalSection对象,当线程需要访问保护数据时,调用临界区对象的lock成员函数,对数据进行保护,防止其他线程访问函数,当执行完操作后,在使用临界区的unlock成员函数,退出保护。
下面是一个简单的例子:

#include "afxmt.h"int array[10],destarray[10];CCriticalSection Section;UINT WriteThread(LPVOID param){ Section.Lock(); for(int x=0;x<10;x++)  array[x]=x; Section.Unlock();}UINT ReadThread(LPVOID param){ Section.Lock(); For(int x=0;x<10;x++)  Destarray[x]=array[x]; Section.Unlock();}

2、互斥量
互斥量和临界区很相似,它不仅可以在同一应用程序的线程间实现同步,还可以在不同的进程间实现同步,从而实现资源的安全共享,在同一进城中建议使用临界区,因为相对而言临界区更节省系统资源,效率更高。
使用互斥对象时,必须创建一个CSingleLock或CMultiLock对象,用于实际的访问控制

3、信号量
信号量的用法和互斥量的用法很相似,不同的是它可以同一时刻允许多个线程访问同一个资源,创建一个信号量需要用CSemaphore类声明一个对象,一旦创建一个了一个信号量对象,就可以用它来对资源的访问进行控制。
首先要创建CSingleLock或CmltiLock对象,然后用创建的对象的lock函数减少这个信号量的计数值unlock反之。
下面是一段示例代码:

#include <windows.h>  #include <process.h>  using namespace  std;  void semaphoreTest(void *ptr)  {      int flag = *(int *)ptr;      HANDLE semaphore = CreateSemaphore(NULL, 2, 2, (LPCWSTR)"streamSemaphore");      WaitForSingleObject(semaphore, INFINITE);      。。。    ReleaseSemaphore(semaphore, 1, NULL);      CloseHandle(semaphore);  }   int main()  {      int flag[] = {1, 2, 3};      for (int i = 0; i < 3; ++i)      {          _beginthread(semaphoreTest, 0, &flag[i]);      }    sleep(INFINITE);           } 
原创粉丝点击