惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 最新话题
C
Cyber Attacks, Cyber Crime and Cyber Security
G
GRAHAM CLULEY
T
Tenable Blog
T
Threatpost
C
CXSECURITY Database RSS Feed - CXSecurity.com
I
Intezer
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
D
Darknet – Hacking Tools, Hacker News & Cyber Security
K
Kaspersky official blog
Security Latest
Security Latest
P
Privacy & Cybersecurity Law Blog
Google Online Security Blog
Google Online Security Blog
SecWiki News
SecWiki News
P
Palo Alto Networks Blog
TaoSecurity Blog
TaoSecurity Blog
Webroot Blog
Webroot Blog
Spread Privacy
Spread Privacy
O
OpenAI News
The Last Watchdog
The Last Watchdog
P
Proofpoint News Feed
C
Check Point Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
人人都是产品经理
人人都是产品经理
S
Security @ Cisco Blogs
Scott Helme
Scott Helme
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
月光博客
月光博客
S
Securelist
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
T
Troy Hunt's Blog
W
WeLiveSecurity
GbyAI
GbyAI
N
News | PayPal Newsroom
Y
Y Combinator Blog
C
Cisco Blogs
H
Help Net Security
The GitHub Blog
The GitHub Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 【当耐特】
Jina AI
Jina AI
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
云风的 BLOG
云风的 BLOG
小众软件
小众软件
N
News and Events Feed by Topic

Whexy Blog

We lost the AIxCC. So, what now? Arm VMM with Apple's Hypervisor Framework Driving WaveShare E‐Paper Display with a Raspberry Pi Pico in MicroPython Use cgroup v2 inside docker containers Annual Hit Piece: Fuzzing Top Conference Paper Debunking Report Solving SSH Key Login Issues on Synology NAS Can SSD Cache Improve Synology NAS Write Speeds? Virtualization is all you need Running Windows Games on Mac Without Virtual Machines Tears of the Kingdom: End of an Era Anonymous CDN Traffic Relay Self-host Relay Service with CDN Home Networking Solution Building Your Own Blog System Connecting Smart Devices to SUSTech Campus Network Function Color Theory Stop Forkin' Around: Faster Creating of Large Processes on Linux PMU Interrupts: How to handle them Using QEMU to run Linux images on M1 Macbook Alligator In Vest - My first research work Experience Using Several Plugins in Complex LaTeX Projects Variance in Rust Understanding Rust Generic Traits SUSTeam: Ultimate Gaming Platform Inline Assembly Language in C React Learning Notes Building a School Bus Schedule App for Apple Watch 12307 Train Ticket Purchase Platform Sakai and Local Folder Synchronization Building a Super Simple OpenJudge in Two Nights Setting Up Remote Backup for macOS Shell Script for Automatically Logging into SUSTech Campus Network Building a Movie Streaming System in the Dorm
Asynchronous Mutex
Whexy · 2021-09-05 · via Whexy Blog

Whexy /

September 05, 2021

Asynchronous programs can also be applied on multi-thread system through "thread pool". However, using mutex in it might be a problem.

Here is the example from Jon Gjengset's live stream "Crust of Rust: async/await".

async fn main() {
  let x = Arc::new(Mutex::new(0));
  let x1 = Arc::clone(&x);
  tokio::spawn(async move {
    loop {
      let x = x1.lock();
      tokio::fs::read_to_string("file").await;
      *x += 1;
      // the lock of x is automatically droped here
    }
  });
  let x2 = Arc::clone(&x);
  tokio::spawn(async move {
    loop {
      *x2.lock() -= 1;
    }
  });
}

Two spawned asynchronous functions are going to change the value in x.

Using spawn allows us to execute the asynchronous functions simultaneously (creating two event loops). Thus we must use Mutex to protect the value of x. But spawn may not give us another thread to run the program since it is "smart". It will decide whether to create another thread to do that or still using the existing one.

Let's say this time; the spawn decides to run the program in just one thread. When the line 7 tokio::fs::read_to_string("file").await; gets executed, the function will yield and get back to the executor (tokio runtime). Then, the executor decides to execute the function in line 15 *x2.lock() -= 1;. Now we encounter a deadlock. The control flow looks like this.

let x = x1.lock(); // async func 1 get the lock
tokio::fs::read_to_string("file").await; // func 1 yields!

// tokio runtime stores the context and switch to func 2

*x2.lock() -= 1; // async func 2 tries to get the lock but fails;
// the thread is blocked.

x2 will wait for the lock to be released. Interestingly, the Operating System never thought that a thread could be executed in such behavior. Usually, the locks are valid among the threads. And once a thread tries to get the lock, the Operating System will block it until the lock is released.

In this specific case, the lock should be released by the thread itself! However, the thread is blocked by the OS, so the lock will never be released! The main reason is that the thread is preemptive scheduled, while the asynchronous functions are cooperate scheduled. The lock is invented for preemptive scheduling patterns.

So this story teaches us that we should be careful with Mutex in asynchronous programming. If you want to use std::Mutex in asynchronous programs, you should never let an await go inside the critical section.

© LICENSED UNDER CC BY-NC-SA 4.0