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

2021-02-20 21:32:59 +08:00
 goldiorl

不好意思题目有点抽象,

一般当一个 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();
}

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

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

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

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

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

你是为了解决是啥问题呢?
fiveelementgid
2021-02-20 23:11:30 +08:00
Concurrency 的设计理念我只看到过
这个 concept 一开始是为了客户端响应体验设计出来的,为了不让操作 freeze(冻掉?)不知道怎么翻译
还有你问的这个不属于开发问题,属于底层实现问题,如果你是 C++的话,自己去找 论文?之类的东西看看
如果你是底层有 virtual machine 的语言(Java 等),建议去看看 runtime 文档,里面有写
ysc3839
2021-02-20 23:12:54 +08:00
@goldiorl C++ 这个是无栈协程,不和线程绑定,可以自己调度。有点类似 js 的 async await,当成解决 callback hell 的辅助工具用也行。
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
2021-02-21 01:43:00 +08:00
同一个 thread 怎么会并发执行呢
你的中文不对,重写

就算是协程也要出栈入栈排队执行,哪里并发
goldiorl
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
2021-02-21 10:30:13 +08:00
感谢各位回复,感谢 v2ex, 对我很有帮助,虽然我也说不清楚我又想清楚了什么,哈哈
geelaw
2021-02-21 10:53:59 +08:00
@goldiorl #9 如果(任何 making sense 的)语言有协程的语言构造(即 async-await ),你是可以马上看出来一段代码中间是否可能被打断的。这里没有 await,所以不可能发生这种事情。

如果代码里有 await,那你是知道线程和协程无配对关系的,自然不会期待 ThreadLocal 能够保护多个协程,因为它不叫 CoroutineLocal 。
geelaw
2021-02-21 10:56:10 +08:00
@goldiorl #9 另外 C++/WinRT 有 co_await resume_background{}; 这种构造,而 .NET 的 awaiter 也可以选择是否返回原来线程,所以并不是必然回到原来的线程。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/754731

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX