前段时间要做个多线程数据共享的例子。多线程之间用过不少,数据同步,是第一次做。
之前看书的时候看到很多这方面的说明,感觉很复杂,一直没去深入。这次要做这个应用了,遇上不少问题。
一开始就是看不懂网上的教程,看了之后,发现人家讲了很多,自己看了,似乎看懂了又没看懂。
嫌麻烦就尝试用一个全局变量来做“忙标志”,要操作数据的线程先把标志置“忙”,操作完之后恢复为“闲”。其它线程看到忙标志就暂停,空跑。
在windows2003写完代码后运气起来“感觉没问题”,而在XP系统下一下子就崩溃了。
多线程的代码调试下来非常麻烦,我也是不懂在delphi环境下该如何调。
后来经过一番摸索,发现用互斥对象来做相对简单些,看了教程加自己摸索了一阵,终于弄懂了,但也不知道懂得对不对。望大家指正。
举个例子而言,
有两个子线程,都是要对同一个全局数据BUFFER进行操作(有写有读),应该怎样避免数据访问冲突呢?
1.全局变量声明。
const
MUTEX_DATA : string = 'P1P2P3C1C2DATA';
var
hMutexData: THandle = INVALID_HANDLE_VALUE;
2.在你的主线程(系统为程序默认创建的第一个线程)创建子线程之前,初始化互斥对象。
hMutexData := CreateMutex(nil, False, PChar(MUTEX_DATA));
该函数的使用请参阅其它资料,注意第二个参数要为False,表示创建的时候不“打开”这个互斥量。
3.在各个线程要操作全局数据BUFFER(或写或读)前等待,请求互斥量。
WaitForSingleObject(hMutexData, INFINITE);
INFINITE表示无限等待。如果当前互斥量处于“空闲”状态,则把互斥对象抢占过来,然后往下执行下面的代码。
如果互斥量处于“非空闲”状态,则一直等待到“空闲”才往下执行代码。该方式不占用CPU时间。好像是跟Windows事件机制有关。
把互斥对象抢占过来之后,别的线程就无法取得互斥对象,要等你当前这段代码执行完毕。
4.在主线程退出前,释放互斥对象。
ReleaseMutex(hMutexData);
说起来,这个过程跟我一开始想的拿个全局变量来做“忙标志”的原理很接近,可为什么我那个方法不行。。。可能没处理好吧。。。懒,没深究。。。
要补充两点:
1.上面讲的是同步一个全局数据,其实如果多个线程访问同一个窗体或同一个控件时,也可以使用这样的方法。它们也是全局数据的一种。
2.上面的第三步加“等待互斥对象”的代码究竟加在哪里是有讲究的。
同一个线程最好只等待一个互斥对象(可以有多个互斥对象)。如果在一个线程中多次调用WaitForSingleObject(hMutexData, INFINITE),那么你就要处理好代码执行顺序的问题,否则很容易死锁。宁愿多创建几个互斥对象,如不同的代码不同的互斥对象。
如:
WaitForSingleObject(hMutexData111, INFINITE);
WaitForSingleObject(hMutexData222, INFINITE);
WaitForSingleObject(hMutexData333, INFINITE);
互斥对象用起来其实很简单。就是没被点透。
希望这篇文章能帮到你。如果我的理解,用法有问题,也希望你能指正一下,不胜感激。
原创
温校宏
2009/11/15