【问题标题】:Threading Differences in Linux Subsystem For WindowsWindows 的 Linux 子系统中的线程差异
【发布时间】:2017-08-18 20:49:19
【问题描述】:

更少的编程问题,更多的是我正在寻求澄清的奇怪问题。考虑以下 C 程序:

#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>

volatile int counter = 0;

void incrementCounter()
{
    counter += 1;
}

void* threadfunc()
{
    for (int i = 0; i < 1000; i++)
    {
        incrementCounter();
    }
}

int main()
{
    pthread_t tids[100];
    printf("Creating Threads...\n");
    for (int i = 0; i < 100; i++)
    {
        pthread_create(&tids[i], NULL, threadfunc, NULL);
    }

    printf("Joining Threads...\n");

    for (int i = 0; i < 100; i++)
    {
        pthread_join(tids[i], NULL);
    }

    printf("Finished. Counter = %d\n", counter);
}

这是我为大学作业写的。它应该显示在写入变量时多个线程不锁定的危险。

我在 Windows 10 上,所以我打开我安装的 Ubuntu Bash,然后运行

$ gcc -std=c99 -pthread main.c
$ ./a.out

打印出来

Creating Threads...
Joining threads...
Finished. Counter = 100000

好的……没错。它不应该是正确的。这应该被打破了!

我一次又一次地运行它,结果相同。 Counter = 100000 每一次!这可能是我一生中唯一一次让我对我的代码正常工作感到失望。

所以我登录了我的学校为 CS 学生共享的 Linux 系统。拉取我的代码,以同样的方式执行它,我得到:

Creating Threads...
Joining threads...
Finished. Counter = 99234

下一次,Counter = 99900,然后是Counter = 100000,然后是Counter = 99082

这就是我所期待的!

所以我的问题:

什么给了? Windows 的 Linux 子系统是什么导致我的代码不中断?

【问题讨论】:

  • 您安装的Ubuntu 是否在具有单个 CPU 的虚拟机中运行?
  • @Lou Linux Subsystem For Windows 不是虚拟机。
  • 标准安装。在具有 4 个物理内核的 i7 上运行。
  • @n.m.:刚刚注意到,直到现在我才知道这个东西存在。据推测,至少根据 OP 的观察,它在后台进行了 some 线程虚拟化。向post a comment here 了解有关内部运作的详细信息也许是个好主意。
  • “我很失望我的代码能正常工作。” - 不可能,因为代码本身不正确。我建议您使用较小的线程池和更多 更大的计数目标。在main 的下一个线程启动之前,您启动的每个线程都已经完成其循环并终止,这是完全可行的。和/或/还使用全局互斥锁锁定每个线程的开头,该全局互斥锁最初锁定在main 中,并且仅在所有线程启动时才释放,每个线程在开始循环之前获得它后立即释放它。

标签: c multithreading ubuntu pthreads windows-10


【解决方案1】:

仍然坏了。它只是碰巧起作用了。您没有保证代码将正确运行或不正确。你[仍然]在线程之间有一个竞态条件

在这里,我使用了两个线程:A 和 B。但是,该示例适用于更多线程。

在 linux 上,你得到了:

thread A        thread B
-------------   --------------
fetch
                fetch
inc
                inc
store
                store

这里,线程 B 的存储将丢弃线程 A 的增量和存储。也就是说,如果原始值为 5,您将得到 6 而不是 [期望] 7。

在 Windows 下,你得到:

thread A        thread B
-------------   --------------
fetch
inc
store
                fetch
                inc
                store

但是,区别只是操作系统调度程序及其策略。没有锁定就没有保证。

在 Windows 下,它在线程 B 启动并运行之前启动线程 A,该线程运行完成,因此您会得到“脱节”行为。

尝试使用更大 [或更小] 数量的线程和更大的线程循环值,您应该会看到一些不同的行为

【讨论】:

  • 我很确定 OP 已经知道这一切,问题是 为什么 Ubuntu-on-Windows 版本没有表现出这种行为。并且涉及到 100 个线程,而不是“线程 A 和 B”。
  • @Lou 感谢您指出这一点。是的,我知道代码被严重破坏了——任务是编写严重破坏的代码。
  • @Craig Estey 你的建议是正确的。我将它增加到 1000 个线程,计数到 10000,我开始看到不正确的结果。这种情况非常罕见——可能有 5% 的时间。
猜你喜欢
  • 2011-09-01
  • 1970-01-01
  • 2010-10-02
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
  • 2017-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多