首页 > 解决方案 > c++ Linux中的线程无限期等待

问题描述

我们必须编写将创建两个线程的程序。第一个线程会从键盘请求字母,然后它会向等待它的第二个线程发送一个信号。然后它将这个字母改成大写字母,如果这个字母不是'E',它会向线程一发送另一个信号。什么会再次运行线程,直到您键入的字母不会是“e”。

两个线程之间的通信有点类似于打乒乓球,或者至少应该如此。

下面我添加一段我写的代码。它还没有完成,但有一个问题我无法修复或找到解决方案。当我尝试运行此代码时,它会卡住。看起来两个线程都在等待信号,所以什么都没有发生。

怎么了?

#include <iostream>
#include <fstream>
#include <string>
#include <pthread.h>
#include <stdlib.h>

using namespace std;

pthread_mutex_t mut;
pthread_cond_t dadam;
pthread_cond_t dudum;

char x;

void *first(void *arg) {
  while(1) {  
    pthread_mutex_lock(&mut);
    pthread_cond_wait(&dadam, &mut);
    cout << "Type a letter\n";
    cin >> x; 
    pthread_mutex_unlock(&mut);
    pthread_cond_signal(&dudum);
  }
}

void *second(void *arg) { 
  while(1) {
    pthread_cond_wait(&dudum, &mut); 
    pthread_mutex_lock(&mut);
    char y;
    y = toupper(x);
    cout << y << endl;
    pthread_mutex_unlock(&mut);
    pthread_cond_signal(&dadam);
  }
}

int main()
{
  pthread_t nun;
  pthread_t nuno;

  pthread_create(&nun, NULL, &first,NULL);
  pthread_create(&nuno, NULL, &second,NULL);
  pthread_cond_signal(&dadam);
  pthread_join(nun, NULL);
  pthread_join(nuno, NULL);

  return 0;
}

标签: c++linuxmultithreading

解决方案


您不会初始化互斥锁或条件变量。它们具有静态持续时间,因此参与默认初始化,但不能保证这会产生可用状态。实现这一点的通用方法是使用pthread_cond_init()and pthread_mutex_init(),但如果默认值足够,那么您还可以使用初始化宏:

pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t dadam = PTHREAD_COND_INITIALIZER;
pthread_cond_t dudum = PTHREAD_COND_INITIALIZER;

您还尝试在dudum不持有指定互斥锁的情况下等待 CV。调用时需要持有互斥锁pthread_cond_wait()

pthread_mutex_lock(&mut);
pthread_cond_wait(&dudum, &mut); 

(不是相反)。

但主要问题似乎是您的实现中的竞争条件。

在其循环的每次迭代中,函数在继续之前first()等待 CV ,并且在循环的每次迭代中,函数在继续之前等待 CV 。如果您可以引导它,这可能会起作用,但是当您第一次启动这两个功能时,任何一个都不能继续等待以发出另一个正在等待的 CV 信号。您从主线程发出信号,但如果主线程在开始等待之前发送信号,则信号将丢失。dadamsecond()dudumdadamfirst()

不足: 建议:

  1. 正确初始化互斥锁和 CV。
  2. 修复函数中互斥范围的问题second();和
  3. main(),在互斥锁的保护下执行线程创建(但不是连接);和
  4. 在函数中first()(仅)将 移动pthread_cond_wait()到循环的末尾(确保适当地扩展互斥锁的范围),这样first()就不必等待信号执行其第一次迭代;和
  5. 删除pthread_cond_signal()from main(),因为它不再需要。

请注意,在pthread_cond_signal()锁定目标 CV 的关联互斥锁的同时执行一段时间是安全的。不需要这样做,但有些人建议将其作为良好做法。


推荐阅读