【问题标题】:Mutex is lock but other threads are entering in critical section互斥锁已锁定,但其他线程正在进入临界区
【发布时间】:2017-09-30 14:37:33
【问题描述】:

我们研究过,如果我们处理多线程问题,那么我们使用一种称为互斥锁的线程同步方法,它允许锁定临界区,以便其他线程不会干扰并进入阻塞状态,直到互斥锁解锁临界区。

但是我在我的程序中做这件事,但是这个程序的输出与互斥锁的概念不匹配。如果我错了,请纠正我。

代码

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>

#define MAX 10 

pthread_mutex_t the_mutex;
pthread_cond_t condc, condp;
int toConsume=0;
int i;

void* consumer(void *ptr) {
pthread_mutex_lock(&the_mutex);
while(i<MAX)
{
    /* protect buffer */
    while (toConsume <= 0) /* If there is nothing in the buffer then  wait */
    {
        printf("Waiting Thread id:%lu \n",pthread_self());
        pthread_cond_wait(&condc, &the_mutex);
    }
   pthread_mutex_unlock(&the_mutex); /* release the buffer */

    sleep(2);

   pthread_mutex_lock(&the_mutex); /* protect buffer */
   toConsume--;
   i++;
 }
 pthread_mutex_unlock(&the_mutex); /* release the buffer */
 pthread_exit(0);
}

int main(int argc, char **argv) {
pthread_t pro, con[3];
pthread_mutex_init(&the_mutex, NULL);
pthread_cond_init(&condc, NULL); /* Initialize consumer condition variable */
pthread_cond_init(&condp, NULL); /* Initialize producer condition variable */

// Create the threads

for(int i=0 ;i<3;i++)
pthread_create(&con[i], NULL, consumer, NULL);

for(int i=0 ;i<3;i++)
pthread_join(con[i], NULL);

return 0;
}

输出

$ ./ex
Waiting Thread id:140580582618880 
Waiting Thread id:140580574226176 
Waiting Thread id:140580565833472 

所有线程都进入临界区,即使互斥体保持其锁定状态。

【问题讨论】:

  • 告诉我pthread_cond_wait 做了什么。
  • 它将通过使用来自其他进程或线程的信号等待某个条件变为真。
  • 锁定一个互斥锁 inside 一个循环并相应解锁 outside 循环通常是一个坏主意——在你的consumer() 函数中,如果while(i&lt;MAX) 循环体重复,您将尝试在 the_mutex 已锁定时锁定它(您不应该这样做)。
  • 错误地将其放入循环中。
  • @suleman 这是全部吗? (提示:否)

标签: c multithreading operating-system pthreads mutex


【解决方案1】:

函数pthread_cond_wait 将在线程等待时解锁持有的互斥锁。这允许另一个线程进入临界区。

使用pthread_cond_wait 的目的是线程需要等待某个条件变为真,然后才能真正执行临界区内的工作。首先测试条件需要锁定互斥锁。但是,如果条件为假,它必须等待某个事件使条件为真。如果它在持有锁的情况下等待,则没有其他线程能够更新状态以使条件变为真,因为更新条件也需要锁定同一个互斥体。

因此,当等待条件变量时,互斥锁被解锁以允许另一个线程获取锁以执行使条件为真的操作。

例如,考虑一个作业队列。线程将锁定互斥锁以从队列中获取作业。但是,如果队列为空,则必须等待作业出现在队列中。这是必须等待的条件,并且可以为此目的使用条件变量。当它在条件变量上调用pthread_cond_wait 时,关联的互斥锁被解锁。

另一个线程希望将作业放入队列。该线程可以锁定互斥体,将作业添加到队列中,向条件变量发出信号,然后解锁互斥体。

当条件变量发出信号时,等待线程被唤醒,pthread_cond_wait 返回并再次持有互斥锁上的锁。它检测到队列非空,可以进入从队列中取出作业的临界区。

【讨论】:

  • 这个解释清除了我的概念,但是有没有办法停止进入临界区中的其他线程,即使其他线程正在等待某个条件变为真。
  • @suleman:它们被停止了,因为它们必须等待相同的条件变为真。
  • 现在假设所有线程都处于等待状态,突然有一个作业进入队列,这里有一些等待时间,这里条件变为真,一个线程接受这个作业并使用 sleep(waiting_time ) 函数,此时另一个作业进入队列,并且通过信号再次条件变为真,那么此时第二个线程也将承担第一个由第一个线程服务的作业。请消除这种误解。
  • @suleman:临界区从队列中删除第一个作业。进入临界区的任何后续线程都不会看到该作业。
  • @suleman:一次只有一个线程可以持有一个互斥锁,所以即使多个线程在条件变量上唤醒,每个线程一次只能从pthread_cond_wait返回一个,随着互斥体变得可锁定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-25
  • 2021-04-16
  • 2010-10-22
  • 1970-01-01
  • 2015-10-08
  • 2013-08-07
相关资源
最近更新 更多