在执行多线程时卡住(Windows 上的 pthread) [英] Get stuck executing multithreads (pthread on Windows)

查看:165
本文介绍了在执行多线程时卡住(Windows 上的 pthread)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望你能帮助我解决我的麻烦.我的程序正在做一些我不太理解的事情.程序目的如下:创建两个线程(task_timer 和 task_read).这些线程必须在标准输出 (stdout) 上显示以下消息:贴 1标签 2标签 1标签 2……"

I hope you will be able to help me in my trouble. My program is doing something I don't really understand. The program purpose is given as below: Create two threads (task_timer and task_read). These threads have to display on the standard output (stdout) the following message : "Tache 1 Tache 2 Tache 1 Tache 2 ..."

代码:

static void* task_timer(void* arg);
static void* task_read(void* p);
struct strShared{
    pthread_mutex_t mut;
    pthread_mutex_t mut2;
    pthread_cond_t synchro;
    pthread_cond_t synchro2;
};


struct strTimer{
    int wt;
    strShared* psh;
};

static void* task_timer(void* p){
    time_t echeance;
    strTimer* timer;
    int time_waiting = 1000;
    time_t  now;
    if(p != NULL){
        timer = p;
        time_waiting = timer->wt; //ms
        echeance = time (NULL) + TIME_OF_THREAD;

        while (1)
        {
            pthread_mutex_lock(&timer->psh->mut);
            printf("Tache 1\n");
            pthread_cond_signal(&timer->psh->synchro);
            pthread_cond_wait(&timer->psh->synchro2, &timer->psh->mut);
            pthread_mutex_unlock(&timer->psh->mut);
        }
    }
    return NULL;
}

static void* task_read(void* p){
    strTimer* timer;
    if(p != NULL){
        timer = p;
        while(1){
            pthread_mutex_lock(&timer->psh->mut);
            pthread_cond_wait(&timer->psh->synchro, &timer->psh->mut);
            printf("Tache 2\n");
            pthread_cond_signal(&timer->psh->synchro2);
            pthread_mutex_unlock(&timer->psh->mut);
        }

    }
    return NULL;
}
int main (void)
{

    pthread_t ttimer;
    pthread_t tread;

    /* TIMER */
    strTimer timer;
    strShared shtimer;
    shtimer.mut = PTHREAD_MUTEX_INITIALIZER;
    shtimer.mut2 = PTHREAD_MUTEX_INITIALIZER;
    shtimer.synchro = PTHREAD_COND_INITIALIZER;
    shtimer.synchro2 = PTHREAD_COND_INITIALIZER;
    timer.psh = &shtimer;
    timer.wt = 1000;

    /* Threads */
    pthread_create(&ttimer, NULL, task_timer, &timer);
    pthread_create(&tread, NULL, task_read, &timer);

   pthread_join(ttimer,NULL);
   pthread_join(tread,NULL);
   return 0;
}

在我看来,这段代码是实现这一目标的好方法.但是,它不起作用然后我想我犯了一些错误.据我所知,它的工作方式如下:

According to me, this code is the good way to achieve this aim. However, it is not working then I guess I did some mistakes. According to me it is working as below:

  1. 两个线程都是并行创建和执行的
  2. Task_read 获取互斥量 mut,等待信号同步并释放互斥量,因为信号从未到达
  3. Task_timer 获取互斥量 mut 并在标准输出上显示Tache 1"
  4. 然后,Task_timer发送信号synchro并等待信号synchro2(释放互斥锁,因为信号从未到达)
  5. Task_read 接收到信号同步并取互斥量 mut 并显示Tache 2"
  6. Task_read 发送信号 synchro2 并释放互斥量 mut 并转到 While 循环的开头
  7. Task_timer 收到信号 synchro2 并释放互斥锁并转到 While 循环的开头

然而,这不是那样发生的.实际上,程序在显示Tache 1"后似乎卡住了.有人可以解释一下为什么会发生这种情况吗?我想我觉得不好,但我想了解...

However, this is not happened like that. Actually, it seems the program gets stuck after displaying "Tache 1". Someone could explain me why this happens please ? I guess I think bad but I would like to understand ...

非常感谢,esc39

推荐答案

让我们看看 task_timer 先获取锁会发生什么.

Let's see what happens when task_timer acquire lock first.

pthread_mutex_lock(&timer->psh->mut);      /*acquires a lock*/                                     /*|*/
printf("Tache 1\n");                       /*output*/                                              /*|*/
pthread_cond_signal(&timer->psh->synchro); /*sends a signal*/                                      /*|*/ /* no one is waiting for the signal on this cond, so the signal is ignored*/
pthread_cond_wait(&timer->psh->synchro2, &timer->psh->mut); /*releases lock and waits for signal*/ /*|*/ pthread_mutex_lock(&timer->psh->mut); /*acquires a lock*/
                                                                                                   /*|*/ pthread_cond_wait(&timer->psh->synchro, &timer->psh->mut); /*releases lock and waits for signal*/
                                                                                                   /*|*/
                                                                                                   /*|*/
                                                                                                   /*|*/
                                                                                                   /*|*/ printf("Tache 2\n"); /*never happens*/
pthread_mutex_unlock(&timer->psh->mut);    /*never happens*/                                       /*|*/ pthread_cond_signal(&timer->psh->synchro2);
                                                                                                   /*|*/ pthread_mutex_unlock(&timer->psh->mut);

死锁.

简单的方法:将您的 pthread_cond_signal() 调用放在临界区之外.将其视为经验法则.当您有几个或多个线程与同一组 mutex/cond 同步时,我很难想象从临界区发出信号是合理的场景.信号和广播的语义就像:嘿,伙计们,我已经完成了我在关键资源上的工作,你们可以继续关注.当线程处于临界区时,通过向 cond 发出信号,它会生成一个错误的语句.因为它没有完成.

Simple recipe: put your pthread_cond_signal() calls outside the critical sections. Consider that as a rule of thumb. When you have a couple or more of threads synchronising with the same set of mutex/cond I can hardly imagine a scenario when it is reasonable to signal from critical section. Semantic of signal and broadcast is like: hey, guys, I'm done with my work on the critical resources, you may follow right on. When the thread is inside critical section, by signalling the cond it makes a false statement. Because it is not done.

顺便说一句,在你的情况下,你需要一个额外的标志来告诉哪个线程应该运行.并且只有在标志告诉轮到另一个线程的情况下才调用 pthread_cond_wait().

BTW, in your case you need an additional flag telling which thread should run. And call the pthread_cond_wait() only in case the flag tells is the other thread's turn.

因此,每个线程的基本算法将是(伪代码):

So, the basic algorithm for each thread would be (in pseudocode):

while(loop_again) {
  do_processing_on_non_critical_resources(); /* it's optional */
  lock(mutex);
  while(not_my_turn) { /* explained later */
    wait(cond,mutex);
  }
  do_processsing_on_critical_resources();
  set_flag_to_other_thread();
  unlock(mutex);
  signal(cond);
  do_processing_on_non_critical_resources(); /* it's optional */
}

not_my_turn 的检查在 while 循环中,而不是简单的 if 检查,因为根据文档,可能存在虚假唤醒从pthread_cond_timedwait()pthread_cond_wait():

The check for not_my_turn is in while loop instead of simple if check, because, according to the documentation, there could be spurious wakeup from the pthread_cond_timedwait() or pthread_cond_wait():

当使用条件变量时,总是有一个布尔谓词涉及与每个条件等待关联的共享变量,如果线程应该继续,则该谓词为真.可能会发生来自 pthread_cond_timedwait()pthread_cond_wait() 函数的虚假唤醒.由于 pthread_cond_timedwait()pthread_cond_wait() 的返回值并不暗示该谓词的任何值,因此应在此类返回时重新评估该谓词.

When using condition variables there is always a Boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed. Spurious wakeups from the pthread_cond_timedwait() or pthread_cond_wait() functions may occur. Since the return from pthread_cond_timedwait() or pthread_cond_wait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.

所以,上面你有一个同步线程的一般情况.但是,对于您的情况,M.KHd 的回答 是正确且充分的.

So, above you have a general case of synchronised thread. However for your case the answer from M.KHd is correct and sufficient.

这篇关于在执行多线程时卡住(Windows 上的 pthread)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆