具有多线程的C -Mutex数据结构

时间:2016-06-23 13:47:53

标签: c multithreading mutex

我有一个我无法解决的问题。 我必须使一些线程共享一个数据结构,问题是: 线程同时执行,它们应该在特定结构中插入数据,但是每个对象都应该插入到互斥锁中,因为如果一个对象存在,则不能重新插入。 我想要创建一个数组,其中线程放置它们正在工作的对象的键,如果另一个线程想要放置它应该等待当前线程完成的相同键。 所以,换句话说,每个线程都为lock元素执行此函数:

void lock_element(key_t key){
  pthread_mutex_lock(&mtx_array);

  while(array_busy==1){
    pthread_cond_wait(&var_array,&mtx_array);
  }
  array_busy=1;
  if((search_insert((int)key))==-1){
        // the element is present in array and i can't insert, 
        //  and i must wait for the array to be freed.
        // (i think that the problem is here)
  }
  array_busy=0;
  pthread_cond_signal(&var_array);
  pthread_mutex_unlock(&mtx_array);
}

在我完成对象后,我使用跟随功能释放了arry中的键:

void unlock_element(key_t key){

  pthread_mutex_lock(&mtx_array);

  while(array_busy==1){
    pthread_cond_wait(&var_array,&mtx_array);                       
  }

  array_busy=1;
  zeroed((int)key);                                     
  array_busy=0;
  pthread_cond_signal(&var_array);
  pthread_mutex_unlock(&mtx_array);
}

这样,每次执行结果都会发生变化(例如:第一次程序插入300对象,第二次插入100对象)。

感谢您的帮助!

更新:

@DavidSchwartz @Asthor我修改了代码如下:

  void lock_element(key_t key){
   pthread_mutex_lock(&mtx_array);
   while((search_insert((int)key))==-1){
         //wait
         pthread_cond_wait(&var_array,&mtx_array);
     }
   pthread_mutex_unlock(&mtx_array);
 }

和...

 void unlock_element(key_t  key){
 pthread_mutex_lock(&mtx_array);

 zeroed((int)key);                                   
 pthread_cond_signal(&var_array);
 pthread_mutex_unlock(&mtx_array);
  }

但不行。它的行为和以前一样。

我还注意到函数search_insert(key)的一个奇怪行为;

  int search_insert(int key){
   int k=0;
   int found=0;
   int fre=-1;
   while(k<7 && found==0){
     if(array[k]==key){
         found=1;
     } else if(array[k]==-1) fre=k;
     k++;
   }
   if (found==1) {
     return -1; //we can't put the key in the array

   }else {
      if(fre==-1) exit(EXIT_FAILURE);
      array[fre]=key;
      return 0;
    }

  }

永远不会进入

  if(found == 1)

2 个答案:

答案 0 :(得分:0)

你有几个选择。

最简单的选择就是在整个操作过程中保留互斥锁。除非你有充分的证据表明你需要更高的并发性,否则你绝对应该选择这个选项。

通常,只允许多个线程完成工作是可能的。这种模式的工作原理如下:

  1. 获取互斥锁。
  2. 检查对象是否在集合中。如果是这样,请使用集合中的对象。
  3. 否则,请释放互斥锁。
  4. 生成对象
  5. 再次获取互斥锁。
  6. 检查对象是否在集合中。如果没有,请添加它并使用您生成的对象。
  7. 否则,丢弃您生成的对象并使用集合中的对象。
  8. 这可能导致两个线程执行相同的工作。在您的用例中这可能是不可接受的,因为它是不可能的(某些工作只能完成一次),或者因为并发性的增加不值得重复工作的成本。

    如果没有别的办法,你可以选择更复杂的解决方案:

    1. 获取互斥锁。
    2. 检查对象是否在集合中。如果是这样,请使用集合中的对象。
    3. 检查是否有任何其他线程正在处理该对象。如果是,则阻止条件变量并转到步骤2.
    4. 表示我们正在处理该对象。
    5. 释放互斥锁。
    6. 生成对象。
    7. 获取互斥锁。
    8. 删除我们正在处理该对象的指示。
    9. 将对象添加到集合中。
    10. 广播条件变量。
    11. 释放互斥锁。
    12. 这可以通过单独的集合来实现,只是为了跟踪正在进行的对象,或者您可以将对象的特殊版本添加到包含指示其正在进行的值的集合中。

答案 1 :(得分:0)

答案基于假设。

考虑这种情况。你有2个线程试图插入他们的对象。线程1和线程2都获得索引为0的对象。然后我们提出了两种可能的场景。

A: 线程1启动,抓取互斥锁并继续插入其对象。它们完成,让下一个线程从互斥锁开始,即2.线程1尝试再次获取互斥锁以释放索引,但是当线程2拥有它时被阻塞。线程2尝试插入其对象但由于采用了索引而失败,因此插入永远不会发生。它释放互斥锁,线程1可以抓取它,释放索引。但是线程2已经尝试过并且无法插入它拥有的对象,这意味着我们总共只能插入1个。

B: 第二种情况。线程1启动,抓取互斥锁,插入对象,释放互斥锁。在线程2抓取它之前,线程1再次抓取它,清除索引并再次释放互斥锁。线程2然后成功抓取互斥锁,在释放互斥锁之前插入它拥有的对象。在这种情况下,我们得到2个插入。

最后,问题在于当一个线程无法插入对象和线程时,if语句内部没有反应,而不是按照它的意图。这样你获得的插入次数就少于预期。