可以从多个线程等待相同的任务 - 等待线程安全吗?

     2023-03-31     151

关键词:

【中文标题】可以从多个线程等待相同的任务 - 等待线程安全吗?【英文标题】:Is it ok to await the same task from multiple threads - is await thread safe? 【发布时间】:2013-05-29 17:32:02 【问题描述】:

等待线程安全吗?似乎 Task 类是线程安全的,所以我想等待它也是线程安全的,但我没有在任何地方找到确认。线程安全也是自定义等待器的要求 - 我的意思是 IsCompleted、GetAwaiter 等方法? IE。如果这些方法不是线程安全的,那么等待是线程安全的吗?但是,我预计不会很快需要自定义等待器。

用户场景示例:假设我有一个异步返回结果的后台任务,然后从多个线程中使用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace scratch1

    class Foo
    
        Task<int> _task;

        public Foo()
        
            _task = Task.Run(async () =>  await Task.Delay(5000); return 5; );
        

        // Called from multiple threads
        public async Task<int> Bar(int i)
        
            return (await _task) + i;
        
    

    class Program
    
        public static void Main(string[] args)
        
            Foo foo = new Foo();

            List<Task> tasks = new List<Task>();
            foreach (var i in Enumerable.Range(0, 100))
            
                tasks.Add(Task.Run(async () =>  Console.WriteLine(await foo.Bar(i)); )); 
            

            Task.WaitAll(tasks.ToArray());
        
    

【问题讨论】:

【参考方案1】:

正如你所提到的,await 足够薄,一开始就看不到线。

await 相关的代码(状态机中编译器生成的代码,以及BCL 中的支持类)一次只能在一个线程上运行。 (从等待返回时可以切换到不同的线程,但之前的运行已经完成)

实际的线程安全取决于您等待的对象。 它必须有一种线程安全的方式来添加回调(或者await一次两次可能会中断)。

此外,它必须只调用一次回调,否则可能会破坏状态机。 (特别是,如果它同时在两个线程上运行它的回调,事情会变得非常糟糕)

Task 是线程安全的。

【讨论】:

您的第一个陈述可能会误导人们认为await 从根本上来说是不安全的......而我认为您的意思是它既不是本质上的安全也不是不安全的——它只是代表正在等待的任何东西,如果那是@ 987654326@,你没事。 当然,谢谢。虽然“将只在一个线程上运行”可能应该是“每次只在一个线程上运行,每次方法调用(对应于状态机的单个实例)”。它当然可以在await 点的线程之间跳来跳去,但它不会在多个线程上同时运行。 (至少不会,除非你严重滥用它......这总是很有趣。)

等待与唤醒案例

...比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,那么线程A与线程B之间就存在线程通信问题。为什么要处理线程间通信:多个线程并发执行时,... 查看详情

java之等待唤醒机制(线程之间的通信)

...比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,那么线程A与线程B之间就存在线程通信问题。为什么要处理线程间通信:多个线程并发执行时,... 查看详情

等待与唤醒机制(线程之间的通信)(代码片段)

线程间通信概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。为什么要处理线程间通信多个线程并发执行时,在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们... 查看详情

等待与唤醒机制

...醒(notify());在有多个线程进行等待时,如果需要,可以使用notifyAll()来唤醒所有的等待线程。wait/notify就是线程间的一种协作机制。等待唤醒中的方法:等待唤醒机制就是解决线程间通信的问题的,使用到的3个方法的含... 查看详情

java中线程安全问题及解决方法线程状态线程间通信(线程等待唤醒机制)(代码片段)

...;要求是某个货被某个线程售卖后,其他线程应该不再可以售卖此个货,但是默认被某个线程售卖后,其他线程还是会售卖此货物,这里不合理,不过有解决的方法),这里的冲突指线程安全问题,... 查看详情

线程池lambda表达式-10(代码片段)

...比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,那么线程A与线程B之间就存在线程通信问题。为什么要处理线程间通信:多个线程并发执行时,... 查看详情

通过等待条件等待多个正在运行的线程

】通过等待条件等待多个正在运行的线程【英文标题】:Waitformultiplerunningthreadsviawaitconditions【发布时间】:2013-07-1608:36:47【问题描述】:我在使用qt同步多个线程时遇到问题(不幸的是3.3.8)。因为启动线程是一项耗时的任务,... 查看详情

从不同线程将值添加到全局集中并等待所有线程完成

...2018-09-3021:05:22【问题描述】:我是线程新手,想知道是否可以使用线程将大量数据拆分为小任务,从而减少处理时间我已将Set拆分为多个集合列表,并且来自执行程序服务的每个线程占用该集合并将该集合添加到另一 查看详情

如果任务产生不同的线程,Serial DispatchQueue 会等待吗

】如果任务产生不同的线程,SerialDispatchQueue会等待吗【英文标题】:WillaSerialDispatchQueuewaitifataskspawnsadifferentthread【发布时间】:2018-11-2721:21:42【问题描述】:串行调度队列将一次执行一项任务。但是,如果队列中有task1和task2怎... 查看详情

买卖包子案例——等待唤醒机制

...果:整个代码写在主线程即main线程(main方法中),当然可以运行; 添加while(true)之后,无限循环:  查看详情

使用 Phaser 等待线程池任务完成

】使用Phaser等待线程池任务完成【英文标题】:WaitforcompletionofthreadpooltasksusingPhaser【发布时间】:2017-03-1015:55:50【问题描述】:只有在提交到线程池的所有任务都完成后,我才想从我的executeTasks()方法返回。请注意,我的线程池... 查看详情

多线程设置线程超时思路

...际执行时间暂时不知道怎么确定花了多久。队列等待时间可以确定,可以从这里入手,大致实现超时时间。比如线程接收的是一个对象,对象中可以设置提交任务到线程池的时间,在线程执行逻辑中,判断当前时间与对象中的时... 查看详情

多个线程等待一个事件?

...:(我认为)我想要的是AutoResetEvent的等价物,多个线程可以等待,所有线程都可以在设置时恢复。我知道这可以通过为每个线程设置一个AutoResetEvent并设置每个线程来实现-但有没有更简单的方法?一种不依赖于事件句柄数组的... 查看详情

Java:一个线程如何等待多个对象?

...ts?【发布时间】:2011-09-1001:10:55【问题描述】:一个线程可以使用Object.wait()进行阻塞,直到另一个线程对该对象调用notify()或notifyAll()。但是如果一个线程想要等到多个对象中的一个发出信号怎么办?例如,我的线程必须等到eith... 查看详情

多个线程可以安全地同时将相同的值写入同一个变量吗?

】多个线程可以安全地同时将相同的值写入同一个变量吗?【英文标题】:Canmultiplethreadswritethesamevaluetothesamevariableatthesametimesafely?【发布时间】:2020-01-0901:11:34【问题描述】:多个线程能否安全地将相同的值同时写入同一个变量... 查看详情

线程间的通信--等待唤醒机制

1.多个线程操作相同的资源,但是操作动作不同,所以存在安全问题例如:publicclassTest{publicstaticvoidmain(String[]args){Resourcer=newResource();Inputin=newInput(r);Outputout=newOutput(r);Threadtin=newThread(in);Threadtout=newThread(out 查看详情

让线程在开始下一组任务之前等待所有任务完成

...述】:我有一个由多个阶段组成的管道。同一阶段的作业可以并行处理。但是必须先完成第1阶段的所有工作,然后才能开始从事第2阶段的工作,等等。我正在考虑使用CountDownEvent同步这项工 查看详情

有多少线程可以等待锁?

】有多少线程可以等待锁?【英文标题】:Howmanythreadscanwaitforlock?【发布时间】:2022-01-0303:37:43【问题描述】:我有一个可以从多个线程同时调用的PLSQLAPI。但是,API中有一段代码我希望一次只能由一个线程访问。我正在使用dbms_... 查看详情