精易论坛
标题:
转载 多线程的那点儿事(之数据同步)
[打印本页]
作者:
Cand
时间:
2012-6-27 10:48
标题:
转载 多线程的那点儿事(之数据同步)
多线程创建其实十分简单,在
windows
系统下面有很多函数可以创建多线程,比如说
_beginthread
。我们就可以利用它为我们编写一段简单的多线程代码,
[cpp] view plaincopyprint?#include <windows.h>
#include <process.h>
#include <stdio.h>
unsigned int value = 0;
void print(void* argv)
{
while(1){
printf("&value = %x, value = %d\n", &value, value);
value ++;
Sleep(1000);
}
}
int main()
{
_beginthread( print, 0, NULL );
_beginthread( print, 0, NULL);
while(1)
Sleep(0);
return 1;
}
复制代码
注意,在
VC
上面编译的时候,需要打开
/MD
开关。具体操作为,【
project
】
->
【
setting
】
->
【
c/c++
】
->Category
【
Code Generation
】
->
【
Use run-time library
】
->
【
Debug Multithreaded
】即可。
通过上面的示例,我们看到作为共享变量的
value
事实上是可以被所有的线程访问的。这就是线程数据同步的最大优势——方便,直接。因为线程之间除了堆栈空间不一样之外,代码段和数据段都是在一个空间里面的。所以,线程想访问公共数据,就可以访问公共数据,没有任何的限制。
当然,事物都有其两面性。这种对公共资源的访问模式也会导致一些问题。什么问题呢?我们看了就知道了。
现在假设有一个池塘,我们雇两个人来喂鱼。两个人不停地对池塘里面的鱼进行喂食。我们规定在一个人喂鱼的时候,另外一个人不需要再喂鱼,否则鱼一次喂两回就要撑死了。为此,我们安装了一个牌子作为警示。如果一个人在喂鱼,他会把牌子设置为
FALSE
,那么另外一个人看到这个牌子,就不会继续喂鱼了。等到这个人喂完后,他再把牌子继续设置为
TRUE
。
如果我们需要把这个故事写成代码,那么怎么写呢?朋友们试试看,
print?while(1){
if( flag == true){
flag = false;
do_give_fish_food();
flag = true;
}
Sleep(0);
}
复制代码
上面的代码看上去没有问题了,但是大家看看代码的汇编代码,看看是不是存在隐患。因为还会出现两个人同时喂食的情况,
[cpp] view plaincopyprint?23: while(1){
004010E8 mov eax,1
004010ED test eax,eax
004010EF je do_action+56h (00401126)
24: if( flag == true){
004010F1 cmp dword ptr [flag (00433e04)],1
004010F8 jne do_action+43h (00401113)
25: flag = false;
004010FA mov dword ptr [flag (00433e04)],0
26: do_give_fish_food();
00401104 call @ILT+15(do_give_fish_food) (00401014)
27: flag = true;
00401109 mov dword ptr [flag (00433e04)],1
28: }
29:
30: Sleep(0);
00401113 mov esi,esp
00401115 push 0
00401117 call dword ptr [__imp__Sleep@4 (004361c4)]
0040111D cmp esi,esp
0040111F call __chkesp (004011e0)
31: }
00401124 jmp do_action+18h (004010e8)
32: }
复制代码
我们此时假设有两个线程
a
和
b
在不停地进行判断和喂食操作。设置当前
flag = true
,此时线程
a
执行到
004010F8
处时,判断鱼还没有喂食,正准备执行指令
004010F8
,但是还没有来得及对
falg
进行设置,此时出现了线程调度。线程
b
运行到
004010F8
时,发现当前没有人喂食,所以执行喂食操作。等到
b
线程喂食结束,运行到
00401113
的时候,此时又出现了调度。线程
a
有继续运行,因为之前已经判断了当前还没有喂食,所以线程
a
继续进行了喂食了操作。所以,可怜的鱼,这一次就连续经历了两次喂食操作,估计有一部分鱼要撑死了。
当然鱼在这里之所以会出现撑死的情况,主要是因为
line 24
和
line 25
之间出现了系统调度。所以,我们在编写程序的时候必须有一个牢固的思想意识,如果缺少必须要的手段,
程序可以任何时刻任何地点被调度
,那此时公共数据的计算就会出现错误。
作者:
ㄣ负二代
时间:
2012-7-11 06:18
好东西。是支持来的
作者:
esummer
时间:
2012-12-15 23:58
这个是C#??
欢迎光临 精易论坛 (https://125.confly.eu.org/)
Powered by Discuz! X3.4