Multithreading 在单个线程上是否可能出现死锁?

Multithreading 在单个线程上是否可能出现死锁?,multithreading,theory,Multithreading,Theory,常见的筛选面试问题是:达到死锁所需的最少线程数是多少 正确答案是2 但从理论上讲,使用一个线程就可以产生死锁吗?根据死锁的定义: 死锁是一种状态,其中一组操作的每个成员 等待其他成员释放锁 只有一个线程无法达到死锁状态 对于单线程,您可能会遇到无限循环 如果我们将协程考虑在内,单线程应用程序确实可能会遇到死锁的情况。大卫·施瓦茨提到了这一点 这完全取决于您如何定义“线程”。例如,考虑使用协同程序处理请求的单线程服务器。一个请求的协同路由可能持有另一个线程的协同路由所需的锁,反之亦然。两个协同程序

常见的筛选面试问题是:达到死锁所需的最少线程数是多少

正确答案是2


但从理论上讲,使用一个线程就可以产生死锁吗?

根据
死锁的定义:

死锁是一种状态,其中一组操作的每个成员 等待其他成员释放锁

只有一个线程无法达到死锁状态

对于单线程,您可能会遇到无限循环

如果我们将协程考虑在内,单线程应用程序确实可能会遇到死锁的情况。大卫·施瓦茨提到了这一点


这完全取决于您如何定义“线程”。例如,考虑使用协同程序处理请求的单线程服务器。一个请求的协同路由可能持有另一个线程的协同路由所需的锁,反之亦然。两个协同程序都不能向前推进,除非另一个能够向前推进


你考虑那些协同程序执行上下文线程吗?是不是?

这里有一个单线程程序,由于pthreads互斥体(默认情况下)是:

#包括
#包括
int main(int,char**)
{  
pthread_mutex_t m;
pthread_mutex_init(&m,NULL);
printf(“锁定非递归互斥锁一次…\n”);
pthread_mutex_lock(&m);
printf(“再次锁定非递归互斥…\n”);
pthread_mutex_lock(&m);//这里会发生死锁,因为我们会一直等待锁定的互斥锁解锁。。。
printf(“您永远不会看到打印的文本,因为我们将在上面陷入僵局\n”);
返回0;
}

(如果将互斥体设置为递归互斥体,OTOH,则此场景将由互斥体处理,并将避免死锁)

考虑以下代码片段:

  #include<signal.h>
  some_struct data;
  int main(){
     sigset(SIGINT, handler);
     computation_fn();
     return 0;
  }
  computation_fn(){
     pthread_mutex_lock(&m);
     update_state(&data);
     pthread_mutex_unlock(&m);
  }
  void handler(int signo){
     pthread_mutex_lock(&m);
     display_state(&data);
     pthread_mutex_unlock(&m);
  }
#包括
一些结构化数据;
int main(){
sigset(SIGINT,handler);
计算_fn();
返回0;
}
计算_fn(){
pthread_mutex_lock(&m);
更新_状态(和数据);
pthread_mutex_unlock(&m);
}
无效处理程序(int signo){
pthread_mutex_lock(&m);
显示_状态(&U)数据;
pthread_mutex_unlock(&m);
}
  • 在上面的代码段中,数据由处理程序访问以显示 因此可以通过互斥来访问。对于更新,它还需要 计算_fn()中的互斥体
  • 现在考虑CudioTyfn()是否需要很长的时间来执行 用户决定提交CNTRL-C,则处理程序()将 执行。因为锁不会从系统中释放 计算_fn(),它将无限期地等待它可用
  • 此外,由于在处理程序使用(借用)与计算线程相同的线程时,程序中没有其他线程从计算线程释放互斥体,因此无法释放此互斥体

最终我们可以看到,通过这种方式,单线程程序可以进入死锁

死锁意味着资源图中的一个循环。这样的循环可以使用单线程创建,例如

    Thread.currentThread().join();

没有任何东西可以阻止单个线程创建互斥体,然后阻止互斥体,但这可能不被认为是死锁。这可能发生在.NET中使用async/await和Task之前,发生在具有同步上下文的线程上。如果使用GOTOs语言,那么我的猜测可能是肯定的:在等待之前跳回标签()你完成了。但是它依赖于语言,而不是在所有上下文中都有效,所以…如果操作组的成员不是线程,而是由单个线程执行的函数呢?例如,考虑两个协同进程在一个线程中运行,每个线程都持有一个锁,另一个线程需要向前推进。为什么这不是僵局?为什么需要多个线程?@DavidSchwartz,对。我同意。如果我们认为协同程序是单线程的。那么,是的。它可以到达死锁。
    Thread.currentThread().join();