多线程的学习2
2017-06-13 18:52
204 查看
继续了解多线程,多线程的通信方式我感觉主要就是全局变量,而且这个使用起来感觉也最方便,也许我的理解可能有误。
多线程的通信方式:
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); }
相关文章推荐
- 多线程学习初步
- 在学习多线程时碰到的难题以及攻克
- 多线程的问题和一些学习感悟
- Java多线程学习笔记1
- 多线程学习中碰到的一个很有意思的问题
- java多线程学习笔记2
- 攻克学习多线程时碰到的难题(zz)
- ASP.NET:一段比较经典的多线程学习代码
- 重新学习多任务和多线程
- 对前一段时间学习网络和多线程编程的总结
- 近期关注:IronPython!|| 学习多线程
- 一段比较经典的多线程学习代码
- 多线程的问题和一些学习感悟
- C语言中的多线程编程--Unix学习总结之五
- JAVA多线程学习初步经典实例
- 攻克学习多线程时碰到的难题 [转]
- 多线程 Thread 学习杂记
- 一段比较经典的多线程学习代码
- Java学习,多线程
- C#多线程学习