简体   繁体   English

为什么这两个线程不同步运行?

[英]Why does these two threads not run synchronously?

I have the following program that spawns two threads to print_something() and they both repeatedly print a specific string: thread 1 prints "Hi\n" and thread 2 prints "Bye\n" :我有以下程序生成两个线程到print_something()并且它们都重复打印一个特定的字符串:线程 1 打印"Hi\n"和线程 2 打印"Bye\n"

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

void *print_something(int *k) 
{
    int n = 100;

    int i;
    if (*k) {
        for (i = 0; i < 100; i++) {
            printf("Hi\n");
        }       
    } else {
        for (i = 0; i < 100; i++) {
            printf("Bye\n");
        }
    }
}

int main()
{
    int x = 1, y = 0;
    pthread_t t1, t2;

    pthread_create(&t1, NULL, print_something, &x);
    pthread_create(&t2, NULL, print_something, &y);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    printf("End of program.\n");

    return 0;
}

I expected them to run synchronously wherein the output in the terminal would be random such as:我希望它们同步运行,其中终端中的 output 将是随机的,例如:

Hi
Hi
Bye
Hi
Bye
...

But instead I always get thread 1 to finish its printing first before thread 2 will start printing:但相反,我总是让线程 1 在线程 2 开始打印之前先完成打印:

Hi
Hi
...
Hi
Hi
Bye
Bye
...
Bye
Bye
End of program.

Why is the first thread blocking the second thread from printing?为什么第一个线程阻止第二个线程打印?

Why is the first thread blocking the second thread from printing?为什么第一个线程阻止第二个线程打印?

Who says it's blocking?谁说屏蔽了? Maybe starting a new thread takes long enough that the first additional thread (running in parallel with the original thread) finishes its printing (to stdout's buffer) before the second additional thread arrives at the point of trying to print anything.也许启动一个新线程需要足够长的时间,以至于第一个附加线程(与原始线程并行运行)在第二个附加线程到达尝试打印任何内容之前完成其打印(到标准输出的缓冲区)。

On the other hand, POSIX does specify that the stdio functions perform operations on streams as if there was a lock associated with each stream that a thread must obtain upon entry to the function and releases upon exit.另一方面,POSIX 确实指定 stdio 函数对流执行操作,就好像每个 stream 都有一个锁,线程在进入 function 时必须获得该锁,并在退出时释放。 Thus, the first thread may indeed be blocking the second via the lock associated with stdout .因此,第一个线程可能确实通过与stdout关联的锁阻塞了第二个线程。

Moreover, when a thread unlocks a lock and then immediately tries to re-acquire the same lock, there is a high probability for that thread to succeed immediately despite other threads contending for the lock.此外,当一个线程解锁一个锁,然后立即尝试重新获取同一个锁时,该线程很有可能立即成功,尽管其他线程争用该锁。 As a result, when an entire loop body starts with acquiring a lock and ends with releasing that lock -- as is the case in your code for the lock associated stdout -- it is common for one thread to be able to monopolize the lock for many loop iterations.因此,当整个循环体以获取锁开始并以释放锁结束时——就像你的代码中与锁关联的stdout的情况一样——一个线程能够独占锁是很常见的。许多循环迭代。

I expected them to run synchronously wherein the output in the terminal would be random such as:我希望它们同步运行,其中终端中的 output 将是随机的,例如:

That's an unreasonable expectation.这是一个不合理的期望。 If two people each need to put in a hundred screws and are sharing a screwdriver, do you think they should hand off the screwdriver after each screw?如果两个人每人要装一百颗螺丝,并且共用一把螺丝刀,你认为他们应该在每颗螺丝后交出螺丝刀吗? It only makes sense to hand off the screwdriver when the one holding the screwdriver is tired.只有当拿着螺丝刀的人累了时,才把螺丝刀交出来才有意义。

Each thread spends the vast majority of its time accessing the console output stream.每个线程的绝大部分时间都在访问控制台 output stream。 It can only do this by excluding the other thread.它只能通过排除其他线程来做到这一点。 The behavior you expect would be atrocious.您期望的行为将是残暴的。

Would they run on the same core?它们会在同一个核心上运行吗? That would require a context switch after every line of output -- the worst performance possible for this code.这将需要在 output 的每一行之后进行上下文切换 - 此代码的性能可能最差。 Would they run on two cores?他们会在两个核心上运行吗? That would mean each core is waiting for the other core to finish with the console for about half the time -- also horrible performance.这意味着每个核心都在等待另一个核心完成控制台大约一半的时间——这也是可怕的性能。

Simply put, you expected your system to find a terrible way to do what you asked it to do.简而言之,您希望您的系统找到一种糟糕的方式来执行您要求它执行的操作。 It found a much more efficient way -- letting one thread keep the console, finish what it was doing, and then letting the other go.它找到了一种有效的方法——让一个线程保留控制台,完成它正在做的事情,然后让另一个线程 go。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM