【问题标题】:threads in c++ Linux waiting indefinitelyc++ Linux中的线程无限期等待
【发布时间】:2018-05-11 20:01:26
【问题描述】:

我们必须编写将创建两个线程的程序。第一个线程会从键盘请求字母,然后它会向等待它的第二个线程发送一个信号。然后它将这个字母更改为大写字母,如果这个字母不是“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 和 C++ 是不同的语言,有不同的处理方法。您打算使用哪个?除了(不必要的)using namespace std 这只是 C 代码。 C++ 有 std::thread 来处理这个问题。
  • 在您致电pthread_cond_wait 之前,您必须检查您要等待的事情是否尚未发生。在pthread_cond_wait 返回后继续之前,您必须检查以确保您想要等待的事情已经发生。条件变量是无状态的,不知道您在等待什么。确保您在需要时且仅在需要时致电 pthread_cond_wait 是您 100% 的责任。模式是pthread_mutex_lock(...); while (something_has_not_happened_yet) pthread_cond_wait(...); ...stuff.. pthread_mutex_unlock(...);
  • im 使用 C。之前用 c++ 尝试过,但经过多次尝试后仍然留下一些不需要的片段,老实说,我混合了我想做的和输入的内容。无论如何对不起问题,谢谢你

标签: c++ linux multithreading


【解决方案1】:

你应该初始化互斥变量。

除此之外,似乎第一个线程将等待事件dadam。 确保为线程 first 生成事件。

【讨论】:

    【解决方案2】:

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

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

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

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

    (不是相反)。

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

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

    不足: 建议:

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

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

    【讨论】:

    • 请参阅 David Schwartz 对您的问题的评论,因为他是对的。我删除的建议不足以使您的代码按照他的描述进行,因此,这还不够。解决问题。
    • 上面列出的大部分问题都是在我尝试自己修复时出现的。最有趣的部分是我试图用老师给我们的帮助代码来做这件事。可悲的是,它根本没有帮助。如果我可以出于好奇问我该怎么做第3点?好吧,我修复了它并且它有效,但我很好奇。无论如何,非常感谢你们俩的帮助。
    • @LukeS,您可以通过在第一个 pthread_create() 之前锁定互斥体 (pthread_mutex_lock()) 并在第二个之后解锁它来执行 (3)。
    • @Josh Bollinger 真的,非常感谢。感谢您的解释,我修复了它并理解了代码和我的想法的问题;)真的谢谢你,并对愚蠢的问题感到抱歉。再次非常感谢,祝您有美好的一天
    猜你喜欢
    • 2011-10-23
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多