Flutter synchronized lock

涉及到多线程时,必须要考虑锁,数据同步。

找到资料:synchronized: synchronized | Dart Package

最基本的一个应用:

  有一个变量a, 当多个线程访问时,必须保证同一时刻只有一个线程在读取/设置(类似于 C# 中的 lock(){} )。我们可以使用 synchronized 来处理就非常容易了。如:

_lock.synchronized(()async{
    //dealing with var a
    //...
});

这里有一个需要注意的地方是,这个同步程序块(程序函数)是异步的,举例下

先生成一个默认的工程,然后添加一个函数,函数的内容如下:

    debugPrint("${DateTime.now().toString()}$_bCounting");

    _lock.synchronized( ()async{//block 1
      _bCounting = !_bCounting;
      debugPrint("1:in lock. changed to: $_bCounting");

      _lock.synchronized( ()async{//block 2
        _bCounting = !_bCounting;
        debugPrint("2:in lock. changed to: $_bCounting");
      });
    });

添加2个变量

  bool _bCounting = false;
  var _lock = Lock();

可以添加一个按钮,然后点击调用上面的函数,结果如下:(按钮点击了2次)

2019-12-05 15:15:38.958 false
1:in lock. changed to: true
2:in lock. changed to: false

2019-12-05 15:15:45.535 false
1:in lock. changed to: true
2:in lock. changed to: false

似乎lock没有起作用。调用了2次,都进入了程序块。

实际问题出在: 2个程序块都没有等待完成,所以实际的情况是 block1 先完成,解锁,再顺利进入 block2

改一下程序,如下:block2 中加了 await

    debugPrint("${DateTime.now().toString()}$_bCounting");

    _lock.synchronized( ()async{
      _bCounting = !_bCounting;
      debugPrint("1:in lock. changed to: $_bCounting");

      await _lock.synchronized( ()async{ //added keyword "await"
        _bCounting = !_bCounting;
        debugPrint("2:in lock. changed to: $_bCounting");
      });
    });

运行结果如下:(按钮点击了2次)

2019-12-05 15:23:22.241 false
1:in lock. changed to: true

2019-12-05 15:23:24.196 true

现在每一次运行时,需要等待block2结束,而 block2 需要的资源需要等block1先结束,互相等待变成了死锁。

2020-10-22 更新:

好像以前理解的有问题  :(  

(21-10-15: 再次回顾了一下,看不出来有问题。。。[Speechless])

下面是一部分代码,在界面上会鼠标点击并调用 onTest() 函数。 注意:在 _test 中的 第二行有一个 await 关键字

  onTest(){
      debugPrint("onTest...");
      _lockLoad.synchronized(() => _test(DateTime.now().microsecondsSinceEpoch) );
      debugPrint("onTest...DONE");
  }

  _test(int tick) async{
      debugPrint("_test... $tick");
      await Future.delayed(Duration(seconds: 3));
      debugPrint("_test... $tick DONE");
  }

下面是执行结果:(鼠标连续点击多点)

onTest...
_test... 1603356293276000
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
onTest...
onTest...DONE
_test... 1603356293276000 DONE
_test... 1603356296279000
_test... 1603356296279000 DONE
_test... 1603356299281000
_test... 1603356299281000 DONE
_test... 1603356302317000
_test... 1603356302317000 DONE
_test... 1603356305321000
_test... 1603356305321000 DONE
_test... 1603356308354000
_test... 1603356308354000 DONE
_test... 1603356311357000
_test... 1603356311357000 DONE
_test... 1603356314393000
_test... 1603356314393000 DONE
_test... 1603356317395000
_test... 1603356317395000 DONE
_test... 1603356320431000
_test... 1603356320431000 DONE
_test... 1603356323433000
_test... 1603356323433000 DONE
_test... 1603356326467000
_test... 1603356326467000 DONE
_test... 1603356329472000
_test... 1603356329472000 DONE
_test... 1603356332511000
_test... 1603356332511000 DONE
_test... 1603356335514000
_test... 1603356335514000 DONE
_test... 1603356338538000
_test... 1603356338538000 DONE

21-10-15:上面的结果说明:每次鼠标点击都会打印

onTest...
onTest...DONE

但是 _test() 函数在第一次执行后 block 住了,导致不会再次执行(进入等待状态)

把 Futre.delay(...) 前面的 await 去掉后,运行结果如下:

onTest...
_test... 1603356559778000
_test... 1603356559778000 DONE
onTest...DONE
onTest...
_test... 1603356560168000
_test... 1603356560168000 DONE
onTest...DONE
onTest...
_test... 1603356560520000
_test... 1603356560520000 DONE
onTest...DONE
onTest...
_test... 1603356560539000
_test... 1603356560539000 DONE
onTest...DONE
onTest...
_test... 1603356560757000
_test... 1603356560757000 DONE
onTest...DONE
onTest...
_test... 1603356561015000
_test... 1603356561015000 DONE
onTest...DONE
onTest...
_test... 1603356561243000
_test... 1603356561243000 DONE
onTest...DONE
onTest...
_test... 1603356561453000
_test... 1603356561453000 DONE
onTest...DONE
onTest...
_test... 1603356561670000
_test... 1603356561670000 DONE
onTest...DONE

(21-10-15: 去掉了 await ,导致_test函数立即执行完成,退出锁定)

把中间调用代码修改如下:

_lockLoad.synchronized(() async => await _test(DateTime.now().microsecondsSinceEpoch) );

结果与上面的相同,如下所示:

onTest...
_test... 1603356851340000
_test... 1603356851340000 DONE
onTest...DONE
onTest...
_test... 1603356851592000
_test... 1603356851592000 DONE
onTest...DONE
onTest...
_test... 1603356851605000
_test... 1603356851605000 DONE
onTest...DONE
onTest...
_test... 1603356851801000
_test... 1603356851801000 DONE
onTest...DONE
onTest...
_test... 1603356851988000
_test... 1603356851988000 DONE
onTest...DONE
onTest...
_test... 1603356852177000
_test... 1603356852177000 DONE
onTest...DONE
onTest...
_test... 1603356852357000
_test... 1603356852357000 DONE
onTest...DONE

(21-10-15:加了 await ,_test() 函数仍然快速结束,从而没有形成互锁等待)

--END--

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值