c++ - 上下文切换是否每次都有效,还是会导致意外行为?

标签 c++ c linux

在下面的代码中,我的 friend 在 linux 中使用上下文切换和互斥锁模拟了死锁情况。

#include <stdio.h>
#include <pthread.h>
pthread_mutex_t l1, l2;
void* func1();
void* func2();

int main()
{
    pthread_mutex_init(&l1, NULL);
    pthread_mutex_init(&l2, NULL);
    pthread_t t1, t2;
    pthread_create(&t1, NULL, func1, NULL);
    pthread_create(&t2, NULL, func2, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
}

void* func1()
{
    pthread_mutex_lock(&l1);
    printf("\nl1 locked in func 1"); // 1
    sleep(1);
    printf("\ntrying to Lock l2 in func 1"); // 2
    pthread_mutex_lock(&l2);
}

void* func2()
{
    pthread_mutex_lock(&l2);
    printf("\nl2 locked in func 2"); // 3
    sleep(1);
    printf("\ntrying to Lock l1 in func 2"); // 4
    pthread_mutex_lock(&l1);
}

问题是,执行后它打印了 Statement 1,3 和 4 但正确的输出应该是语句 1,3 和 2

但是当我将 func2 中的 sleep 值更改为 sleep(4) 时,它工作正常。

如果我不写语句 2 和 4,在执行语句 1 后打印出来,但是应该打印语句 1 和 3。

后来把func2的sleep(1)改成sleep(4),再改回sleep(1)就变成正确的工作状态了...

所有这些意想不到的行为还是有原因的... 或者纠正所有这些行为的简单解决方案将帮助我理解。 谢谢。

最佳答案

当您生成线程时,无法保证线程会按照您生成它们的顺序开始执行。有时会发生,有时不会。不能保证 1 在 3 之前出现。唯一可以保证 func1 在调用 pthread_create 之后的任何时候都会在其自己的线程中调用>pthread_join 将不会返回,直到 func1 在该线程中返回。 func2 也是如此。您绝对不能保证其中一个线程会先于另一个线程开始运行。

sleep 不是一个足够的同步机制。 sleep 被定义为让进程等待至少 X 秒。操作系统让您的进程多等待 10 次是完全合法的。不太可能,但有可能发生。特别是在繁忙的系统上。混合使用 sleep 和线程,任何事情都可能发生。由于很可能(但绝对不能保证)线程彼此运行的时间非常接近,并且系统中的计时器没有无限精度,因此它们的 sleep 很可能是计划在“同一时间”结束(“同一时间”是一个非常危险的术语,但在这种情况下,它意味着某个定时器中断的同一滴答声)。所以线程将一起被唤醒,但不能保证哪个线程会先于另一个被唤醒。而且无论哪一个先于另一个被唤醒,仍然无法确定哪一个会先开始运行。如果其中一个线程先于另一个线程运行,那么运气肯定会在这里用完。

通过在 printfs 的开头而不是末尾换行,您没有正确刷新标准输出(这是从哪里来的?很多人无缘无故地在 stackoverflow 问题中这样做)。在 printfs 的末尾添加一个换行符,并且由于您的标准输出很可能是行缓冲的,因此 printfs 将在行尾刷新。

你还有一堆除了在最后导致死锁之外没有明显功能的互斥体。

事实上,代码的编写方式完全有可能(尽管不太可能)func2 开始在线程中运行,锁定 l2,打印并休眠并且再次打印,锁定 l1 并在任何线程开始运行 func1 之前返回。这将导致 func1 不打印任何内容,因为它会在尝试锁定 l1 时挂起。

关于c++ - 上下文切换是否每次都有效,还是会导致意外行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40283110/

相关文章:

c++ - 奇怪的线程问题

linux - 如何检测 xterm resize in-band

Black Hat Python 书中的 Python 嗅探

linux - 如果硬件支持,QNativeGesture 是否可以在 Linux/Windows 上运行?

c++ - 我可以对不同的网址使用相同的 curl 句柄吗? (试图从一个网址的多个页面下载数据)

c++ - gpu 蒙皮的矩阵计算

java - libjvm.so 中的 SIGSEGV Java fatal error 导致 JVM 频繁崩溃

c - Mac OS X x86-64 中指令指针的寻址

c - 如何判断套接字是否关闭

c - 如何理解用它定义 x 和位运算?