6

根据 POSIX,

销毁当前没有线程阻塞的初始化条件变量应该是安全的。

此外,指定信号和广播操作以解除阻塞在条件变量上的一个/所有线程。

因此,在我看来,以下形式的自同步销毁应该是有效的,即调用pthread_cond_destroy

  1. 在一个成功的信号之后,在等待或信号线程中,恰好一个线程在 cond var 上被阻塞。
  2. 广播成功后立即在任何等待线程或广播线程中。

当然,这假设没有其他服务员到达,并且之后不会执行进一步的信号,应用程序负责保证如果使用pthread_cond_destroy.

我是否正确地认为破坏在这些情况下是有效的?还有其他关于条件变量的自同步销毁场景需要注意吗?

最后,对于在不破坏的情况下取消映射共享映射可能有意义的进程共享条件变量,是否可以合理预期取消映射在相同上下文中有效,破坏将有效,或者如果同一进程中有多个线程,则必须进一步同步(地址空间)正在使用相同的映射并希望在上述上下文之一中取消映射?

4

3 回答 3

2

不,我认为您的大多数假设都不正确。从条件变量返回pthread_cond_signalpthread_cond_broadcast不表示任何线程尚未从条件变量中“解除阻塞”,即要解除阻塞的线程不再需要访问该变量。该标准仅说“应解除阻塞”,而不是“在此调用成功返回时,它们将被解除阻塞”。后者对实现有很大的限制,因此可能有充分的理由将其按原样制定。

所以我认为从你描述的场景中只有一个是有效的,即单独阻塞的线程或进程在被唤醒后破坏了条件。

于 2011-09-29T18:17:40.410 回答
0

虽然我同意您对这种语言的解释(以及 Open POSIX 测试套件的解释),但使用将取决于实现。因此,这里是一些主要实现的简要介绍:

安全的

  • nptl -如果在条件下仍有线程阻塞,pthread_cond_destroy()将返回。EBUSY破坏责任将传递给由 not unblocked 发出信号的线程。
  • pthread-win32 MSVC -如果在条件下仍有线程阻塞,pthread_cond_destroy()将返回。EBUSY发出信号但未解除阻塞的线程将在pthread_cond_destroy()将控制权返回给应用程序之前执行。

安全但阻挡

  • Darwin libc-391 -如果在条件下仍有线程阻塞,pthread_cond_destroy()将返回。EBUSY没有为阻塞但有信号的线程做任何规定。
  • Dietlibc 0.27 -如果仍有线程在该条件下被阻塞,pthread_cond_destroy()将返回。EBUSY没有为阻塞但有信号的线程做任何规定。

可能不安全

  • Android - 取决于__futex_wake_ex同步的系统实现。因此pthread_cond_broadcast()必须阻塞,直到所有线程都被唤醒(但没有释放它们的互斥体)。
  • 各种win32实现——很多依赖PulseEvent()函数来实现pthread_cond_broadcast()。这有一个已知的竞争条件

怪人

  • OSKit 0.9 - 安全但EINVAL如果pthread_cond_destroy()在仍被引用的条件变量上调用则返回

编辑

如果我正确阅读了您的评论,主要问题是是否pthread_cond_wait()可以在条件变量返回之前解除阻塞之后访问条件变量。答案是肯定的。该例程假定其参数将保持有效。

这意味着在广播之后,您的线程不能假设条件变量未被其他线程使用。

当您调用 时pthread_cond_broadcast(),您不会获取关联的互斥锁。等待条件变量的线程将按顺序执行,每个线程都按顺序获取关联的互斥锁。因为您的服务员可能会相互阻塞,所以您的广播线程可能会继续执行,而服务员仍处于pthread_cond_wait()互斥锁上的阻塞状态(但不等待条件)。


编辑 2

[...]在相同的情况下,取消映射是有效的,破坏是有效的,这是否合理?

根据编辑 1 中的推理,我认为这不是一个合理的期望。如果您被排除在外,则肯定需要额外的同步pthread_cond_destroy()

于 2011-10-14T20:16:28.233 回答
0

评论(不回答):

这就是你的想法吗?

全球的:

// 受 m 保护:
pthread_mutex_t m;
pthread_cond_t c;
bool about_to_pthread_cond_wait = false;
bool condition_waited_on = false;

线程 A:

pthread_mutex_lock (&​​m);
{ // 锁定区域
    about_to_pthread_cond_wait = true;
    而(条件_waited_on){
        // pthread_cond_wait(&m, &c)在这里分解:
        __pthread_mutex_cond_wait_then_unlock (&​​m, &c);
            // 解锁区域
        pthread_mutex_lock (&​​m);
    }
}
pthread_mutex_unlock (&​​m);

线程 B:

for (bool break_loop = false; !break_loop;) {
    pthread_mutex_lock (&​​m);
    { // 锁定区域
        condition_waited_on = 真;

        如果(about_to_pthread_cond_wait){
            pthread_cond_signal (&c);
            pthread_cond_destroy (&c);
            break_loop = true;
        }
    }
    pthread_mutex_unlock (&​​m);

    pthread_yield();
}

编辑:

我假设pthread_cond_wait (&m, &c);这样做:

__pthread_mutex_cond_wait_then_unlock (&​​m, &c);
pthread_mutex_lock (&​​m);

__pthread_mutex_cond_wait_then_unlock将监视 CV 的信号,然后解锁互斥锁,然后进入睡眠状态。

如果 CV 有一个内部互斥锁__pthread_mutex_cond_wait_then_unlock并且pthread_cond_signal必须在内部锁定,那么我假设__pthread_mutex_cond_wait_then_unlock是:

pthread_mutex_lock (&​​c.int_mutex);
{ // c.int_state 的锁定区域
    __register_wakeup_cond (&c.int_state);
    pthread_mutex_unlock (&​​m);
}
pthread_mutex_unlock (&​​c.int_mutex);
// 不会再触及 c.int_state

__sleep_until_registered_wakeups ();

并且pthread_cond_signal做:

pthread_mutex_lock (&​​c.int_mutex);
{ // CV 内部状态的锁定区域
    __wakeup_registered (&c.int_state);
}
pthread_mutex_unlock (&​​c.int_mutex);

然后pthread_cond_destroy只会在__pthread_mutex_cond_wait_then_unlock使用完毕后调用c.int_state

于 2011-10-15T14:04:34.963 回答