1

我正在阅读Thread Synchronization《Unix 环境中的高级编程》一书。

在本节中,有一个将互斥锁与动态分配的对象一起使用的示例。我对此也有一些疑问。

在这里,我分享发生的事件时间表(从上到下)以解释我的疑问:

  1. 已创建线程 1。
  2. Thread1 创建一个 mutex var 对其进行初始化并将其放在全局列表中,以便其他人可以使用它。
  3. 现在 Thread1 获得了一个锁来使用共享数据结构,比如说ds。Thread1 需要做大量的工作ds,即 Thread1 将长时间获取这个锁。
  4. 现在,虽然 Thread1 仍然获得了锁,但 Thread2 被创建了。
  5. 现在Thread2也想用ds。
  6. 所以 Thread2 必须首先增加显示对 ds 的引用的计数器增加。为此(根据本书),它首先需要mutex_t在增加计数之前使用相同的变量获取锁。
  7. 但是由于 Thread1 已经在这个变量上获得了锁mutex_t,所以当 Thread2lock()在递增计数之前调用时,它必须等到 Thread1 解锁锁。

疑点

  1. 关于他在谈论哪个全局列表(意味着只是制作任何列表并将其引用传递给所有线程或任何特定列表)
  2. 当 Thread1 创建锁变量时,它将计数设置为 1。然后 Thread2 正在等待将此计数增加到 2。但是假设在执行当前工作之后 Thread1 不需要使用 ds。因此,在解锁之前,它也会减少计数或先解锁,然后foo_rele()再次调用锁定并减少计数。现在有可能在 Thread2 增加计数之前,Thread1 减少它。如果是(根据我),那么我的数据结构将被破坏?所以我认为这本书的这个例子有一点错误。如果我们使用不同的 mutex_var 来增加计数会更好吗?
4

3 回答 3

2

答:我认为在“全局列表”一词下,作者理解线程之间共享的所有变量。

例子:

struct foo* shared_foo; /* This pointer is shared between all threads */

struct foo* foo_alloc(void)
{
   /* This pointer is local to the thread which allocates the memory */
   struct foo *fp;

    if ((fp = malloc(sizeof(struct foo))) != NULL) {
        /* whatever */
    }
    /* local pointer value returned */
    return(fp);
}

/* probably somewhere in the code the shared pointer (on the 'global list') is initialized this way */
shared_foo = foo_alloc();

B. 嗯...我真的不明白你说什么。你能把你的场景写成一个列表吗?在我看来f_count,在初始化期间设置为标志“此互斥锁正在使用中”。因此,当互斥体空闲时,该f_count值设置为 1。当Thread1获取锁时,它的值设置为 2。当它释放锁时,该值设置回 1。有效f_count值为:1(初始化和空闲)和 2 (已初始化且忙)。为了释放互斥锁,您只需foo_rele在它被占用时调用两次(f_count= 2)或在它空闲时调用一次(f_count= 1)。然后f_count值达到 0 并且互斥体被移除。

于 2012-12-29T12:02:36.337 回答
2

对,所以示例 11.10 就是关于结构 foo 中的内容。每个结构都有一个锁,因此线程 1 要对对象进行操作,线程 1 需要在对象内持有互斥锁。

给出的示例不完整,我可以理解您的困惑。在线程不再需要该对象之前,不应调用 foo_rele。如果另一个线程想要使用 foo,它应该调用 foo_hold() 来增加引用计数 (fp->count++)。是的,有一个竞争条件,线程 2 可能想要得到它,而线程 1 正在释放它。

这对于多线程编程来说绝对是不寻常的——一个线程很可能会删除你想在你的线程中工作的东西,除非代码是专门为避免这种情况而编写的。避免例如包括对象列表的锁定,如果我的线程持有列表锁定,其他线程不能添加或删除列表中的东西(并且不应该搜索列表,因为我可能只是添加或删除某些内容,并且不能保证列表是一致的)。

我希望这有帮助。

于 2012-12-29T12:15:28.143 回答
2
  1. 线程共享内存,因此任何全局变量对于同一进程中的所有线程都是可见的(因此不需要将指针传递给每个线程)。

  2. 使用互斥锁时,您必须相信线程可以按任何顺序锁定互斥锁(POSIX 不保证任何特定顺序)。因此,线程 1 完全有可能在任何其他线程获得对互斥锁的访问权之前创建、使用和销毁该结构。

PS我理解你的疑惑。我在代码片段中真正缺少的是另一个互斥锁实际上阻止了同时写入结构。

于 2012-12-29T12:36:39.237 回答