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

单核并发是不是不会产生"线程不安全”的问题?

  •  
  •   guyeuro · 2017-06-26 11:28:18 +08:00 · 8114 次点击
    这是一个创建于 2702 天前的主题,其中的信息可能已经有所发展或是发生改变。

    单核下 一个 CPU 核执行并发,在微观上来看还是串行的 这样是不是不会导致”线程不安全“? 只有多核并发才会导致线程不安全?

    40 条回复    2017-06-27 15:35:26 +08:00
    mokeyjay
        1
    mokeyjay  
       2017-06-26 11:42:52 +08:00 via Android   ❤️ 4
    …你是不是没有搞懂线程和并发的区别?
    guyeuro
        2
    guyeuro  
    OP
       2017-06-26 11:55:42 +08:00
    @mokeyjay 哪里没有搞懂?
    bazingaterry
        3
    bazingaterry  
       2017-06-26 12:00:39 +08:00 via iPhone
    锁这玩意,可比多核 CPU 早设计出来...
    hjc4869
        4
    hjc4869  
       2017-06-26 12:00:58 +08:00 via Android
    会,你的非线程安全的代码执行了一半,这时一个时钟中断信号来了,切到别的线程去了,然后另一个线程就把你这个线程用的变量破坏了
    clearbug
        5
    clearbug  
       2017-06-26 12:01:49 +08:00 via Android
    啥是并发?
    啥是并行?
    啥是线程安全?
    楼下来解释
    zwzmzd
        6
    zwzmzd  
       2017-06-26 12:05:39 +08:00 via iPhone
    单核异步?所有代码块都是先后执行的,不存在同时执行两个代码块的问题,块内不用考虑线程安全问题。

    但实际中,为了性能考虑代码块的粒度都会尽量的小,还是会碰到相似问题
    zwzmzd
        7
    zwzmzd  
       2017-06-26 12:08:00 +08:00 via iPhone
    @zwzmzd 发现看错题意了。
    即使单 cpu,操作系统也会按时间分片模拟出多核并发的效果,所以假设是不成立的
    maxxxxx
        8
    maxxxxx  
       2017-06-26 12:08:25 +08:00 via iPhone
    实际上很多下游开发者是没有多核概念的。
    Lonely
        9
    Lonely  
       2017-06-26 12:53:11 +08:00
    去搞清楚概念再来,好吗?
    wwqgtxx
        10
    wwqgtxx  
       2017-06-26 13:40:09 +08:00 via iPhone
    除非你的单核并发是不允许抢占式的,否则一样会产生线程不安全

    举个简单的例子,程序 1 执行 i++,程序 2 也执行 i++
    当程序 1 将 i 值读取出来并运算后改为写入的时候,系统抢占式把控制权给个程序 2,程序 2 完整的执行完了 i++,随后系统将控制权交回给程序 1,此时的程序 1 并不知道自己被打断了,也不知道 i 已经被修改,还把之前计算好的值写入,最后结果就是 i 只加了 1,而不是加了 2
    momocraft
        11
    momocraft  
       2017-06-26 13:51:49 +08:00
    如果你不做保证线程安全的事,就没什么东西是线程安全
    hand515
        12
    hand515  
       2017-06-26 13:57:33 +08:00
    无法保证一段代码执行的原子性
    gogohigh
        13
    gogohigh  
       2017-06-26 14:02:56 +08:00
    Concurrent 和 Parallel 是两个概念
    SKull4
        14
    SKull4  
       2017-06-26 14:09:32 +08:00
    应该不是科班的
    blackjar
        15
    blackjar  
       2017-06-26 14:56:48 +08:00
    你应该是混淆了并发跟并行 并发在只是 cpu 时序有交叉
    facetest
        16
    facetest  
       2017-06-26 15:46:08 +08:00
    建议先补补基础知识
    20015jjw
        17
    20015jjw  
       2017-06-26 18:06:42 +08:00 via Android
    @wwqgtxx 两个程序之间不能互相 access 内存吧 操作系统的虚拟内存不就 是为了避免这件事情发生的吗...
    yushiro
        18
    yushiro  
       2017-06-26 18:39:15 +08:00 via iPhone
    @20015jjw 同一个程序的不同代码块可以啊,比如电子商城购买虚拟物品,同时扣款的例子,就是那个 i++的实际案例
    stephenyin
        19
    stephenyin  
       2017-06-26 18:53:31 +08:00
    @20015jjw 考虑单进程多线程的情况!
    hjc4869
        20
    hjc4869  
       2017-06-26 19:17:02 +08:00 via Android
    @20015jjw 两个进程可以共享内存啊
    wwqgtxx
        21
    wwqgtxx  
       2017-06-26 19:17:45 +08:00
    @20015jjw 第一,大量存在单进程多线程的情况,第二,还存在进程间共享内存的情况
    honeycomb
        22
    honeycomb  
       2017-06-26 19:27:02 +08:00 via Android
    单核不会出现 CPU 缓存不一致的情况,因为只有一个 CPU 核心。
    20015jjw
        23
    20015jjw  
       2017-06-26 19:51:06 +08:00 via Android
    @wwqgtxx
    @hjc4869
    @stephenyin
    @yushiro

    程序不是 process 么 thread 当然可以共享 但是不同 process 不是都是自己一个虚拟内存么... 这个帖子里就写了啊
    https://stackoverflow.com/questions/11566780/process-vs-thread-can-two-processes-share-the-same-shared-memory-can-two-thr

    当然我只学过简单的操作系统 想想有修改器的存在大概 process 之间肯定也能互相 access 的吧 但是感觉可能是违背操作系统设计规范的...
    kaneg
        24
    kaneg  
       2017-06-26 20:05:17 +08:00 via iPhone
    单核线程冲突的概率应该会小一些,但不会消失,毕竟不是原子性的操作会有可能被分配到 CPU 的两个时间片被两个线程分别抢占。
    其次,在多核 CPU 出现之前多线程的同步问题就出现了。
    wwqgtxx
        25
    wwqgtxx  
       2017-06-26 20:17:25 +08:00 via iPhone
    @20015jjw 程序是 program 进程才是 process
    hjc4869
        26
    hjc4869  
       2017-06-26 20:39:26 +08:00
    @20015jjw 但是同一个物理内存页可以被映射到两个不同的进程的地址空间里啊
    acess
        27
    acess  
       2017-06-26 20:56:38 +08:00
    @20015jjw 有 WriteProcessMemory、CreateRemoteThread 等 API 可以用。
    powergx
        28
    powergx  
       2017-06-26 20:59:22 +08:00
    你只要保证你的内存地址数据不会被篡改,100/1000 个线程 都是安全的
    situliang
        29
    situliang  
       2017-06-26 21:09:10 +08:00
    是时候补习一波操作系统了
    yushiro
        30
    yushiro  
       2017-06-26 21:41:33 +08:00 via iPhone
    @20015jjw 不同的 process 的确如你所说,但是 web server 是同一个 process 处理大量请求(同一个域名站点),所以会发生我说的情况
    mazyi
        31
    mazyi  
       2017-06-27 00:17:11 +08:00 via iPhone
    2333,看书去
    20015jjw
        32
    20015jjw  
       2017-06-27 00:59:34 +08:00 via Android
    @hjc4869 这不就违背了虚拟内存的定义么...
    msg7086
        33
    msg7086  
       2017-06-27 01:03:08 +08:00
    不管操作系统怎么保护内存,也有可能两个程序读写同一个文件造成线程不安全的。
    hjc4869
        34
    hjc4869  
       2017-06-27 01:38:27 +08:00 via Android
    @20015jjw 并没有,因为共享内存之后两个进程的地址空间仍然是独立的,虚拟内存的定义并没有规定物理页一定被某个地址空间独占。
    20015jjw
        35
    20015jjw  
       2017-06-27 02:57:18 +08:00 via Android
    @hjc4869 对 但是系统会控制不让一段物理内存被俩程序同时使用啊 http://www.read.seas.harvard.edu/~kohler/class/05s-osp/notes/notes9.html 注意粗体
    > The different processes' memory spaces must be isolated from each other, and from the kernel.
    我 os 课的理解就是 虽然每个 process 看内存都是和系统内存一样大的 比如 0x0000-0xffff 但是俩程序不用满整个系统内存的时候 俩程序所占内存的真实地址永远不会重叠 即便在他们自己眼中可能都在 0x00ff 的地方写东西 但是这俩 00ff 由于虚拟内存的关系 在实际内存中的位置不一样
    hjc4869
        36
    hjc4869  
       2017-06-27 04:24:44 +08:00 via Android
    @20015jjw 我没说地址空间自己会重叠,我指的是现代 OS 在进程主动要求的前提下 OS 会允许两个独立的进程将同一部分物理内存页映射到它们各自的地址空间内。这个叫做 shared memory,是一类非常常用的跨进程通讯手段,通常搭配其它同步、互斥方式,在对数据交换有非常高的性能要求时会使用。比如 Linux 下的 X11,在本机就是使用 MIT-SHM 扩展,利用共享内存交换数据,其原理就是将相同的物理内存页同时映射到多个进程的地址空间。

    因此上面说的跨进程 i++问题是可能存在的

    具体的 API 参考:
    Windows: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366551(v=vs.85).aspx
    Linux: http://man7.org/linux/man-pages/man7/shm_overview.7.html
    wwqgtxx
        37
    wwqgtxx  
       2017-06-27 07:16:19 +08:00
    @20015jjw 只能说你看的“操作系统设计规范”可能已经过时了,在实际工作中,进程直接 share memery 是非常常见的事情,有些高级语言甚至直接在标准库中提供了接口,比如 Python 的 multiprocessing.Value, multiprocessing.Array 都可以直接直接在两个或者多个进程直接直接共享同一块内存,以减小本机程序之间 RPC 调用带来的不必要的性能损耗
    wwqgtxx
        38
    wwqgtxx  
       2017-06-27 07:20:14 +08:00
    而且两个进程直接会产生线程不安全的情况并不是只有同时读写同一块内存区域这一种,如果同时读写同一个 FILE,或者同时读写同一个 MMAP 分配的空间,同时读写一个共享的 socket 都可以造成线程不安全,以及父进程和子进程同时读写同一个打开的句柄或者管道
    icegreen
        39
    icegreen  
       2017-06-27 10:10:34 +08:00
    收获一枚面试题~
    20015jjw
        40
    20015jjw  
       2017-06-27 15:35:26 +08:00 via Android
    @wwqgtxx 嘛 入门课 我也知道有 process 之间分享内存的 只是老师表示这个课不考虑 谢谢你提供的知识啦
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1711 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 16:50 · PVG 00:50 · LAX 08:50 · JFK 11:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.