卡住执行多线程(在Windows上使用pthread)

时间:2017-06-12 14:33:14

标签: c multithreading synchronization pthreads

我希望你能帮助我解决问题。我的程序正在做一些我不太懂的事情。 计划目的如下: 创建两个线程(task_timer和task_read)。 这些线程必须在标准输出(stdout)上显示以下消息: “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;
}

据我所知,这段代码是实现这一目标的好方法。然而,它没有工作,我想我做了一些错误。根据我的说法,它的工作原理如下:

  1. 两个主题都是以并行的方式创建和执行的
  2. Task_read接受互斥锁,等待信号同步并释放互斥锁,因为信号永远不会到达
  3. Task_timer使用互斥锁并在标准输出上显示“Tache 1”
  4. 然后,Task_timer发送信号同步并等待信号synchro2(因为信号永远不会到达而释放互斥锁)
  5. Task_read接收信号同步并获取互斥锁并显示“Tache 2”
  6. Task_read发送信号synchro2并释放互斥锁并转到While循环的开头
  7. Task_timer接收信号synchro2并释放互斥锁并转到While循环的开头
  8. 然而,事情并非如此。实际上,在显示“Tache 1”后程序似乎被卡住了。有人可以解释一下为什么会这样吗?我想我觉得不好但我想明白......

    非常感谢, esc39

2 个答案:

答案 0 :(得分:0)

如果您不熟悉多线程,我建议不要使用条件变量。您不需要为所描述的目标使用任何条件变量。因此,删除两个线程中的pthread_cond_wait和pthread_cond_signal行。

相反,您可以在解锁每个线程中的互斥锁后添加睡眠功能。对于例如task_read可以修改为:

pthread_mutex_lock(&timer->psh->mut);    
printf("Tache 2\n");
pthread_mutex_unlock(&timer->psh->mut);
usleep(10000);

答案 1 :(得分:0)

让我们看看task_timer首先获得锁定时会发生什么。

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它会产生错误的声明。因为没有完成。

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

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

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()

  

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

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