与其说是编程问题,不如说是我正在寻求澄清的怪事。考虑以下 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 子系统有什么原因使我的代码不会中断?
最佳答案
它还是坏了。它恰好起作用了。您没有保证代码将正确运行或不正确。您[仍然]在线程之间存在竞争条件。
在这里,我使用了两个线程: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,该线程一直运行到完成,因此您会得到“不相交”的行为。
尝试使用更多 [或更少] 的线程数和更大的线程循环值,您应该会看到一些不同的行为
关于c - 适用于 Windows 的 Linux 子系统中的线程差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45764860/