【问题标题】:Can multithreading be implemented on a single processor system?多线程可以在单处理器系统上实现吗?
【发布时间】:2013-04-13 13:47:43
【问题描述】:

我一直遵循这样的概念,即多线程只能在多处理器系统上实现,其中每个线程分配多个处理器,并且每个线程可以同时执行。在这种情况下没有调度,因为每个线程都有单独的资源专用于它。 但我最近在某处读到它,我也可以在单处理器系统上执行多线程。 这是正确的吗?如果是,那么单处理器和多处理器系统有什么区别?

【问题讨论】:

  • 是的,简而言之,感知并发与实际并发。
  • 如果不可能的话,那么 Windows 95 就是一个巨大的幻觉。 (如果你把多处理算作多线程,那么原始的 unix 也是一种幻觉。)
  • [link] (qnx.com/developers/docs/qnxcar2/…) 图片比文字更有力量

标签: c windows multithreading winapi


【解决方案1】:

当然,它可以在单处理器系统上完成,实际上这样更容易。它的工作方式与运行多个进程相同——内核通过定时器中断或其他类似机制暂停一个,保存其机器状态,并用另一个先前保存的状态替换它——唯一的区别是两个同一进程的线程共享相同的虚拟内存空间,使任务切换更加高效。

多处理器系统上的多线程实际上要困难得多,因为您会遇到从多个 cpu/内核同时访问内存的问题,以及由此产生的所有令人讨厌的内存同步问题。

【讨论】:

  • 非常感谢。这很有帮助
  • 不,您一定是误读了,因为您转述的陈述绝对是错误的。
  • ⁺¹ 用于«定时器中断»。整个互联网都没有提到硬件切换是如何完成的。我以为它是某种计时器,但即使是维基百科也是沉默的。
  • 如果 2 个线程在一个处理器上运行...不需要同步吗?
  • 从@Barath 帖子中得到答案。
【解决方案2】:

您可以在四核系统上拥有四个以上的活动线程。 调度,除非你能保证进程不会尝试创建比处理器更多的线程。

是的,您可以在单核计算机上拥有多个线程。

单处理器和多处理器系统的区别在于,多处理器系统一次确实可以做不止一件事。它一次可以做 N 件事,其中 N 是处理器内核的数量。单处理器内核一次只能做一件事。正如 WhozCraig 在他的评论中所说,这是实际并发和感知并发之间的区别。

【讨论】:

  • 非常感谢,我现在大致了解了事情是如何完成的
【解决方案3】:

我最近在某处读到它,我可以在单线程上执行多线程 处理器系统也是如此。这是正确的吗?如果是,那么是什么 单处理器和多处理器系统的区别?

是的,您可以在单处理器系统上执行多线程。

在多处理器系统中,多个线程同时在不同的内核上执行。 例如,如果有两个线程和两个核心,那么每个线程将在单独的核心上运行。

在单处理器系统中,多个线程一个接一个地执行,或者等待一个线程完成或被操作系统抢占,这取决于线程优先级和操作系统策略。但是正在运行的线程会产生一种错觉,即它们同时运行,相对于用户空间应用程序所需的应用程序响应时间。

时间比较(示例):

如果两个线程每个执行耗时 10us,那么在 2 处理器系统上,净耗时为 10us

如果两个线程每个执行耗时 10us,那么在 1 个处理器的系统上,净耗时为 20us

【讨论】:

  • 非常有帮助。谢谢你:)
  • Chrome 在进程中运行标签,而不是线程。线程提高稳定性的说法是错误的。一个线程不可能崩溃并让其余线程继续运行。由于一个进程的所有线程共享一个公共地址空间,它们都可能受到任何一个线程破坏内存的影响。此外,由线程“崩溃”引起的非自愿终止会终止整个进程,而不仅仅是单个线程。
  • @R.. 好的,我已经删除了有争议的部分......也许我没有足够的阅读来备份和证明线程的稳定性......
  • 我能看到线程“提高稳定性”的唯一方法是简化代码并降低错误的可能性。编写在自己的线程中运行的同步逻辑比异步的、事件驱动的状态机逻辑要容易得多,这可以转化为更安全、更稳定的程序。但是,如果其中一个调用 UB,线程不会给您任何安全性。
  • 我认为 BarathBushan 的回答很重要,人们应该避免投反对票:(
【解决方案4】:

这是一个非常简化的示例。它实际上是我正在构建的程序的原型。它是单线程中协作多任务的实现。

main 只需将 quit 标志设置为 false,并填充函数指针数组(任务),然后调用 loop

loop 使用setjmp 设置非本地跳转的返回点(函数的跳转out 返回到执行中的先前位置),然后继续调用第一个任务(函数)。

每个任务都以yield() 结尾。也就是说,实际上没有任何任务功能return。它们不仅不包含return; 语句(这很好,因为它们是void 函数,即过程),而且即使return 存在,它们也不会到达return,因为yield 跳回到setjmp 调用,这次为loop 中的if 语句生成1。由if 语句控制的语句在重新进入while 循环之前选择不同的任务。

因此,每个任务函数都会运行多次,让 dispatcherif(setjmp... 语句)选择要运行的新任务。

#include <stdio.h> 
#include <setjmp.h> 

jmp_buf dispatch; 
int ntasks; 
void (*task[10])(void); 
int quit; 

void yield(void) { 
    longjmp(dispatch, 1); 
} 

void loop() { 
    static int i = 0; 
    if(setjmp(dispatch)) 
        i = (i+1) % ntasks; 
    while(!quit) 
        task[i](); 
} 

int acc = 0; 

void a(void) { 
    if (acc > 10) quit = 1; 
    printf("A\n"); 
    yield(); 
} 
void b(void) { 
    acc *= 2; 
    printf("B\n"); 
    yield(); 
} 
void c(void) { 
    acc += 1; 
    printf("C\n"); 
    yield(); 
} 

int main() { 
    quit = 0; 
    ntasks = 3; 
    task[0] = a; 
    task[1] = b; 
    task[2] = c; 
    loop(); 
    return 0; 
} 

此示例与单处理器多任务计算机系统之间的区别在于,真正的处理器支持在执行过程中中断任务并稍后从同一位置恢复。在将任务作为单个函数的 C 语言仿真中,这实际上是不可能的。但是,这些任务可以由一系列 C 函数组成,每个函数都交给调度程序(可能是一个函数指针数组,或者一个链表)。

【讨论】:

  • 您能否添加某种形式的描述或评论来准确解释这应该显示和做什么?谢谢。
  • 编辑了一些解释。 (如果需要,我可以添加更多。)
  • 看起来没有任何方法可以从yield() 返回,所以每个线程都必须在调用yield 之前完成。因此,无法一次拥有多个活动线程,也无法在它们之间切换。所以你可以通过让任务返回(而不是调用yield)来让事情变得更简单,根本不使用setjmp/longjmp
【解决方案5】:

是的,你完全可以。 很久以前(Win 95?)我们从协作多任务到多线程,因为总是有人搞砸了协作部分。 您计算机上的每个程序都至少有一个线程。可能更多。 CPU 会在所有这些线程之间不停地切换,每秒几百万次。如果他们没有任何事情可做,它甚至可能会闲置一段时间。

多核系统仅意味着其中两个或多个线程可能并行运行。

但是,这样做给您带来的好处要少得多。在单核机器上使用多线程可以做的就是模拟多任务。

多任务处理足以防止 GUI 线程因为长时间运行的操作而锁定。但是,实现起来通常很复杂,除非您从编译器或语言(如 C# async...await)获得一些帮助。 结果,许多 GUI 程序员只是使用多线程和调用来伪造多任务。如果该代码在单核或多核上运行并不重要。

最重要的是,多任务处理不适合 CPU 密集型操作。但是 95% 的异步问题都不受 CPU 限制。它们是网络或磁盘绑定的。 在单核计算机上,多线程也无助于 CPU 绑定的东西。如果您有两个线程都需要 100% 的 CPU 时间(相同的程序或不同的程序)但只有一个内核来运行它们,那么 CPU 只需在两者都以 49% 的运行时间和剩余的 2% 运行之间切换其他只做一点点的线程。

最后只有极少数问题实际上可以是多线程的。只需尝试对斐波那契数列进行多线程处理(每对一个线程),而不会使它变得更慢、需要更多内存和更复杂。

tl;博士; 您需要多线程和多核计算机来解决 CPU 绑定问题。 大多数异步问题不受 CPU 限制。多任务处理就足够了。即使在单核机器上,您也可以使用线程完全执行多任务。

【讨论】:

    【解决方案6】:

    在单个处理器上的多线程进程中,处理器可以在线程之间切换执行资源,从而实现并发执行。并发表示不止一个线程在进行,但这些线程实际上并没有同时运行。线程之间的切换发生得足够快,以至于线程可能看起来同时运行。

    在共享内存多处理器环境中的同一个多线程进程中,进程中的每个线程都可以在单独的处理器上并发运行,从而实现并行执行,这才是真正的同时执行。当进程中的线程数小于或等于可用处理器数时,操作系统的线程支持系统确保每个线程运行在不同的处理器上。例如,在使用四个线程编程并在具有两个双核处理器的系统上运行的矩阵乘法中,每个软件线程可以同时在四个处理器核上运行以同时计算一行结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      • 2013-07-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-01
      • 2015-08-09
      相关资源
      最近更新 更多