【问题标题】:C -Mutex data structure with multithreadingC - 多线程互斥数据结构
【发布时间】:2016-06-23 13:47:53
【问题描述】:

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

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);
}

在我完成对象后,我使用以下函数释放数组中的键:

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

  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)

【问题讨论】:

  • 当您已经在使用互斥锁时,为什么还需要 array_busy 变量?
  • 为什么这被否决了?
  • 互斥锁(mtx_array)用于锁定变量array_busy,只有被锁定才能使用这个变量。
  • 您的代码毫无意义。您对array_busy==1 的任何检查都不会永远触发,因为没有线程解锁互斥锁,而array_busy 的值不是零,并且没有线程访问或修改array_busy 而不持有互斥锁。
  • 您粘贴的代码不完整。您在 if 语句(或 search_insert 调用)中丢失了代码,即使您怀疑可能是错误所在。我也猜想那里的代码会解释很多你粘贴的关于array_busy的代码。

标签: c multithreading mutex


【解决方案1】:

你有几个选择。

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

通常,可以只允许多个线程来完成这项工作。这种模式是这样工作的:

  1. 获取互斥体。
  2. 检查对象是否在集合中。如果是这样,请使用集合中的对象。
  3. 否则,请释放互斥锁。
  4. 生成对象
  5. 再次获取互斥锁。
  6. 检查对象是否在集合中。如果没有,请添加它并使用您生成的对象。
  7. 否则,请丢弃您生成的对象并使用集合中的那个。

这可能会导致两个线程做同样的工作。这在您的用例中可能是不可接受的,因为这是不可能的(某些工作只能完成一次),或者因为并发性的收益不值得重复工作的成本。

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

  1. 获取互斥体。
  2. 检查对象是否在集合中。如果是这样,请使用集合中的对象。
  3. 检查是否有其他线程正在处理该对象。如果是,请阻止条件变量并转到第 2 步。
  4. 表明我们正在处理对象。
  5. 释放互斥锁。
  6. 生成对象。
  7. 获取互斥体。
  8. 删除我们正在处理对象的指示。
  9. 将对象添加到集合中。
  10. 广播条件变量。
  11. 释放互斥锁。

这可以通过单独的集合来实现,以跟踪哪些对象正在进行中,或者您可以将对象的特殊版本添加到包含指示它正在进行中的值的集合中。

【讨论】:

    【解决方案2】:

    答案是基于假设。

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

    答: 线程 1 启动,获取互斥体并继续插入其对象。他们完成,让下一个线程从互斥锁中通过,即 2。线程 1 尝试再次获取互斥锁以释放索引,但由于线程 2 拥有它而被阻塞。线程 2 尝试插入他们的对象,但由于索引被占用而失败,因此插入永远不会发生。它释放互斥体,线程 1 可以抓住它,释放索引。但是线程 2 已经尝试插入它拥有的对象但未能成功,这意味着我们总共只能插入 1 次。

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

    最后,问题在于当线程未能插入对象和线程时,if 语句内部没有反应,没有做它应该做的事情。这样,您获得的插入次数将少于预期。

    【讨论】:

      猜你喜欢
      • 2023-02-06
      • 1970-01-01
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      • 2016-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多