V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
goldiorl
V2EX  ›  问与答

请教个问题,什么语言、情况下同一个 thread 会被用于并发执行多个独立逻辑

  •  
  •   goldiorl · 2021-02-20 21:32:59 +08:00 · 1205 次点击
    这是一个创建于 1154 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不好意思题目有点抽象,

    一般当一个 thread 执行一个函数 /方法,应该从头执行到完。一段代码可能会被多个线程访问。thread 上下文切换是操作系统或者是语言底层实现的。

    现在我的问题是想请教一下,有没有什么语言的执行模型,会导致一个(同一个) thread 可不可能并发访问一段代码多次呢?一个 thread 在执行一个函数的中途,保存 context, 又去重新执行这个函数,这里的重新执行是指真的从头执行,非递归嵌套关系。请问这可能吗

    为了避免 xy 问题,其实真正想问的是,这种情况下想用 threadlocal 来控制资源竞争是不是可能失效?

    class C {
    ThreadLocal<Long> example = new ThreadLocal<>();
    }
    
    C c;
    
    void logic() {
    	example.set(System.currentTimeMills());
    	//此处 thread 保存上下文,切换,同一个 thread 从头跑 logic()第二次, 跑到相同位置,再返回第一次跑 logic()的上下文
        example.get(); //这个 get()可能得到上一次跑的时候的值
        example.remove();
    }
    

    请问这种情况有什么语言会有这种情况发生吗

    12 条回复    2021-02-21 10:56:10 +08:00
    ysc3839
        1
    ysc3839  
       2021-02-20 21:43:05 +08:00
    C++20 coroutine 配合线程池 (线程可重复执行不同的函数,执行完不会主动退出) 的话有可能出现。
    比如一个 coroutine 在线程池中 co_await 某个对象,它会返回,假如此时这个 coroutine 的新实例又被提交执行了,那有可能在同一个线程中从头执行同一段代码。
    goldiorl
        2
    goldiorl  
    OP
       2021-02-20 22:46:03 +08:00
    @ysc3839 怕的就是这个,coroutine 和线程池混用,而不是 1-1

    不过其他语言的 coroutine 好像都是几乎和线程并列的一个抽象层
    geelaw
        3
    geelaw  
       2021-02-20 23:01:03 +08:00 via iPhone
    ThreadLocal 在那个语言里的意思很可能是 受那个语言托管的线程-local,而不是 操作系统线程-local,就像是操作系统线程也不是指处理器线程。在这种定义下你的问题不存在。

    async-await 这个语法很可能本来就没有规定每次 await 之后所在的(被语言托管的)线程。比如 UI 相关的代码里,由于 UI 只可以在 UI 线程操作,await 通常会回到原来的线程进行。
    cabing
        4
    cabing  
       2021-02-20 23:03:22 +08:00
    go 启动很多协程就会出现吧。

    如果需要重复执行也可以重量级的 fork 分叉进程池=。=

    你是为了解决是啥问题呢?
    fiveelementgid
        5
    fiveelementgid  
       2021-02-20 23:11:30 +08:00 via Android
    Concurrency 的设计理念我只看到过
    这个 concept 一开始是为了客户端响应体验设计出来的,为了不让操作 freeze(冻掉?)不知道怎么翻译
    还有你问的这个不属于开发问题,属于底层实现问题,如果你是 C++的话,自己去找 论文?之类的东西看看
    如果你是底层有 virtual machine 的语言(Java 等),建议去看看 runtime 文档,里面有写
    ysc3839
        6
    ysc3839  
       2021-02-20 23:12:54 +08:00 via Android
    @goldiorl C++ 这个是无栈协程,不和线程绑定,可以自己调度。有点类似 js 的 async await,当成解决 callback hell 的辅助工具用也行。
    secondwtq
        7
    secondwtq  
       2021-02-21 01:39:53 +08:00
    这么说吧,这个所谓的“thread”,概念上并不是“操作系统”实现的,而是由语言规范定义的,语言规范可以用“thread”这个名字指代与操作系统线程完全不同的抽象(比如 CUDA 也有“thread”这种东西 ...),操作系统或者语言的 RTS 仅仅是个实现细节。

    而“thread local”同样也是语言规范定义的抽象,同样和操作系统线程没有直接关系。

    我本来应该说一句“这个回复假设问题里的‘thread’和‘thread local’指编程语言或其标准库提供的设施”,但我发现没法说,因为这个问题的存在就已经说明楼主已经把编程语言的抽象和操作系统的抽象搞混了。这是两个不同的命名空间,混用不同命名空间中的概念,就可能出现楼主担心的问题。

    而“thread local”之所以叫这个名字,他就应该是对应(同一个命名空间里的)“thread”概念的。所以一个正常的编程语言里面,“thread local”配合“thread”使用是没有问题的。如果这么做不安全,你可以给设计者发个 Email,问他“你也喜欢肖战吗?”
    fucUup
        8
    fucUup  
       2021-02-21 01:43:00 +08:00 via Android
    同一个 thread 怎么会并发执行呢
    你的中文不对,重写

    就算是协程也要出栈入栈排队执行,哪里并发
    goldiorl
        9
    goldiorl  
    OP
       2021-02-21 10:28:07 +08:00
    @fucUup "就算是协程也要出栈入栈排队执行" 这不就是并发?我并不是说“并行"

    @secondwtq 哈哈。最后一个无聊的笑话你到时给了我一点启发。多谢了。不过其实我没有混淆,如果我没有引入任何操作系统的概念,就想说是 user space green thread (not native thread). 一个 thread 依旧会有一个 thread local, 这个 thread 依旧可以被语言托管而用于重复执行逻辑, 我觉得 @ysc3839 说的那个情况是对的.

    @cabing 我就是想问问 thread local 的安全性啊!我完全同意说有协程的话会出现这种问题。然而 java 没有协程,也没有 fiber(暂) ,所以看样子没有安全性问题.

    @geelaw "ThreadLocal 在那个语言里的意思很可能是 受那个语言托管的线程-local,而不是 操作系统线程-local,就像是操作系统线程也不是指处理器线程。" 你说的一开始都同意,不过这个问题为什么你会认为不存在(我觉得前几楼说的协程的情况就是)。"async-await 这个语法很可能本来就没有规定每次 await 之后所在的(被语言托管的)线程" await 之后应该是回到原线程的。
    goldiorl
        10
    goldiorl  
    OP
       2021-02-21 10:30:13 +08:00
    感谢各位回复,感谢 v2ex, 对我很有帮助,虽然我也说不清楚我又想清楚了什么,哈哈
    geelaw
        11
    geelaw  
       2021-02-21 10:53:59 +08:00 via iPhone
    @goldiorl #9 如果(任何 making sense 的)语言有协程的语言构造(即 async-await ),你是可以马上看出来一段代码中间是否可能被打断的。这里没有 await,所以不可能发生这种事情。

    如果代码里有 await,那你是知道线程和协程无配对关系的,自然不会期待 ThreadLocal 能够保护多个协程,因为它不叫 CoroutineLocal 。
    geelaw
        12
    geelaw  
       2021-02-21 10:56:10 +08:00 via iPhone
    @goldiorl #9 另外 C++/WinRT 有 co_await resume_background{}; 这种构造,而 .NET 的 awaiter 也可以选择是否返回原来线程,所以并不是必然回到原来的线程。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2914 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 08:45 · PVG 16:45 · LAX 01:45 · JFK 04:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.