首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++多线程-数据同步

C++多线程-数据同步

作者头像
cwl_java
发布2020-01-15 10:47:47
7670
发布2020-01-15 10:47:47
举报
文章被收录于专栏:cwl_Javacwl_Java

多线程创建其实十分简单,在windows系统下面有很多函数可以创建多线程,比如说_beginthread。我们就可以利用它为我们编写一段简单的多线程代码,

#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。 如果我们需要把这个故事写成代码,那么怎么写呢?朋友们试试看,

while(1){  
    if( flag == true){  
        flag = false;  
        do_give_fish_food();  
        flag = true;  
    }  
  
    Sleep(0);  
}  

上面的代码看上去没有问题了,但是大家看看代码的汇编代码,看看是不是存在隐患。因为还会出现两个人同时喂食的情况,

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之间出现了系统调度。所以,我们在编写程序的时候必须有一个牢固的思想意识,如果缺少必须要的手段,程序可以任何时刻任何地点被调度,那此时公共数据的计算就会出现错误。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-01-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档