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

具有多线程的C-Mutex数据结构,c,multithreading,mutex,C,Multithreading,Mutex,我有一个无法解决的问题。 我必须让某个线程共享一个数据结构,问题是: 线程是同时执行的,它们应该在一个特定的结构中插入数据,但是每个对象都应该插入互斥环境中,因为如果一个对象一直存在,就不能重新插入。 我曾经考虑过创建一个数组,其中线程放置它们正在工作的对象的键,如果另一个线程想要放置相同的键,它应该等待当前线程完成。 因此,换句话说,每个线程都为lock元素执行此函数: void lock_element(key_t key){ pthread_mutex_lock(&mtx_ar

我有一个无法解决的问题。 我必须让某个线程共享一个数据结构,问题是: 线程是同时执行的,它们应该在一个特定的结构中插入数据,但是每个对象都应该插入互斥环境中,因为如果一个对象一直存在,就不能重新插入。 我曾经考虑过创建一个数组,其中线程放置它们正在工作的对象的键,如果另一个线程想要放置相同的键,它应该等待当前线程完成。 因此,换句话说,每个线程都为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@Ashor我修改代码如下:

  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)的一个奇怪行为


你有两个选择

最简单的选择就是在整个操作过程中保持互斥。除非有强有力的证据表明您需要更大的并发性,否则您绝对应该选择此选项

通常,只允许多个线程执行工作是可能的。此模式的工作原理如下:

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

    如果没有其他办法,您可以使用更复杂的解决方案:

  • 获取互斥
  • 检查对象是否在集合中。如果是,请使用集合中的对象
  • 检查是否有其他线程正在处理该对象。如果是,则阻止条件变量并转至步骤2
  • 指示我们正在处理该对象
  • 释放互斥锁
  • 生成对象
  • 获取互斥
  • 删除我们正在处理该对象的指示
  • 将对象添加到集合中
  • 广播条件变量
  • 释放互斥锁

  • 这可以通过一个单独的集合来实现,只是为了跟踪哪些对象正在进行,或者您可以向集合中添加一个特殊版本的对象,该对象包含一个表示正在进行的值。

    答案基于假设

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

    A: 线程1启动,获取互斥对象并继续插入它们的对象。它们完成后,让互斥体的下一个线程通过,即2。线程1尝试再次获取互斥锁以释放索引,但由于线程2拥有该索引而被阻止。线程2尝试插入其对象,但由于索引被获取而失败,因此插入从未发生。它释放互斥锁,线程1可以捕获它,释放索引。然而,线程2已经尝试插入它拥有的对象,但失败了,这意味着我们总共只得到1次插入

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


    最后,问题在于当线程未能插入对象和线程时,if语句内部没有反应,没有执行它的本意。这样你得到的插入比预期的少。

    当你已经在使用互斥锁时,为什么你需要
    array\u busy
    变量?为什么会被否决?互斥锁(mtx\u array)用于锁定变量array\u busy,我只能在被锁定的情况下使用这个变量。你的代码毫无意义。您对
    array\u busy==1
    的任何检查都无法触发,因为没有线程在
    array\u busy
    具有除零以外的任何值时解锁互斥锁,并且没有线程在不持有互斥锁的情况下访问或修改
    array\u busy
    。您粘贴的代码未完成。if语句(或search_insert调用)中缺少代码,甚至您怀疑可能是错误。我还猜测,那里的代码将解释您粘贴的许多关于array_busy的代码。
      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)