生产者消费者只有互斥体

时间:2013-10-28 18:08:59

标签: c pthreads mutex

我想不出这个问题的合理解决方案。 有两个流 - 主要和孩子。 他们必须依次显示如下信息:

... 等等10次。

您只能使用pthread互斥锁,不要使用空闲周期。 仅在初始化阶段允许空闲循环。 谁 - 谁知道一个很好的解决方案?

3 个答案:

答案 0 :(得分:3)

我想我明白了......大提示是“在初始化阶段只能空闲。”

首先,对互斥锁的限制是你必须在你锁定的同一个线程中解锁。所以线程中的每个unlock()都必须与lock()配对,我们必须拥有相同数量的(或者我们会陷入僵局)。

这意味着我们可以防止线程多次打印的唯一方法是确保每个线程始终保持至少一个MUTEX。如果线程B在任何时候释放了它的所有互斥锁,然后CPU切换到线程A,它就可以无限期地运行。

我们不能在没有死锁的情况下使用2个互斥锁,但是我们可以用3执行此操作。

父线程:

    bool initDone = false;
    lock(m1);
    lock(m2);
    spawnChild();
    while (!initDone)
        sleep();
    while (true) {
        print("Parent");
        unlock(m1);
        lock(m3);
        unlock(m2);
        lock(m1);
        unlock(m3);
        lock(m2);
    }

子线程:

    lock(m3);
    initDone = true;
    while (true) {
        lock(m1);
        unlock(m3);
        lock(m2);
        print("Child");
        unlock(m1);
        lock(m3);
        unlock(m2);
    }

我们从拥有锁1和2的父母和拥有3的孩子开始。然后他们轮流释放并获取锁:父亲给孩子给了锁1,孩子给了父3的锁3,父给儿童给了锁2,孩子给了将1锁定到父级,父级将锁3给予子级,子级将锁2给予父级,重复。

一个有趣的问题;我打赌你现在看到条件变量的吸引力,因为它们使这个变得无足轻重。

答案 1 :(得分:0)

您可能需要更具体地了解要求。如果切换输出是唯一的实际要求,那么这样的事情应该有效(有点伪代码):

const char *strings[2] = { "Parent", "Child" };
pthread_mutex_t m; // needs to be properly initialized, of course
int which = 0;

thread_func()
{ while (1)
  { lock(&m);
    printf("%s\n", strings[which])
    which = !which;
    unlock(&m);
  }
}

您可以根据需要生成任意数量的线程,输出将继续交替。但是,线程不一定会交错一次迭代。尝试仅使用互斥体进行适当的单次迭代交错并且没有yield函数(pthreads没有指定)有点困难......

答案 2 :(得分:0)

您需要的是2个线程(父线程和子线程)允许彼此执行。

这是伪代码,您可以自由使用任何所需的锁定原语。

//global variables and initializations
parent_lock = UNLOCKED; //This allows your first print to be from parent
child_lock = LOCKED;

parent_counter = 0; //to count the number of prints 
child_counter = 0;

//Parent should do this                  |        //Child should do this
while(1)                                 |while(1)
{                                        |
spin: if(parent_lock == LOCKED)          |spin: if(child_lock == LOCKED)
      {                                  |      {
         //spin till child unlocks you   |      //spin till parent unlocks you
          goto spin;                     |          goto spin;
      }                                  |      }
      else                               |      else
      {                                  |      {
          print("PARENT");               |          print("CHILD");
          parent_counter++;              |          child_counter++;
          //lock yourself allow the other|          //lock yourself allow the other
          parent_lock = LOCKED;          |          child_lock = LOCKED;
          child_lock = UNLOCKED;         |          parent_lock = UNLOCKED;
          if (parent_counter == 10)      |          if (child_counter == 10)
          {                              |          {
              break;//printed 10 times   |              break;     
          }                              |          }
       }                                 |       }
}                                        |}

//PARENT has printed 10times wait for    |//CHILD has printed 10times wait for 
//child                                  |// parent

PS :*我假设您可以自由旋转我已经完成的锁定,如果不是这样的话,您需要修改上述算法来进行睡眠和唤醒而不是旋。
*您可以选择pthread lock原语来初始化parent_lock和child_lock *为了使程序正确,我们需要假设赋值语句是原子的Ex:child_lock = LOCKED语句是原子的。

非常重要:查看父级中的顺序:

parent_lock = LOCKED;
child_lock = UNLOCKED;

和它在子线程中的对应部分。 如果你交换这两行,那么你可以DEADLOCK !!!!,因为父和子的一系列混合执行(由于OS调度程序)。