何时可以使用cond var来同步自己的销毁/取消映射?

时间:2011-09-29 14:00:02

标签: c synchronization pthreads posix condition-variable

根据POSIX,

  

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

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

因此,在我看来,以下形式的自同步破坏应该是有效的,即呼叫pthread_cond_destroy

  1. 信号成功后,在等待或信令线程中,当cond var上只有一个线程被阻塞时<。li>。
  2. 广播成功后,立即在任何等待线程或广播线程中。
  3. 当然,假设没有其他服务员到达,之后不再执行任何信号,如果使用pthread_cond_destroy,应用程序负责保证。

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

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

3 个答案:

答案 0 :(得分:2)

不,我不认为你的大部分假设都是正确的。从pthread_cond_signalpthread_cond_broadcast返回并不表示任何线程尚未从条件变量“解除阻塞”,即要解除阻塞的线程不再需要访问该变量。该标准仅表示“应解锁”,而不是“在通过此呼叫成功返回时,它们将被解锁”。后者对于实现来说是非常严格的限制,所以可能有一个很好的理由就是按原样制定它。

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

答案 1 :(得分:0)

虽然我同意您对此语言的解释(以及Open POSIX测试套件的解释),但使用依赖于实现。因此,这里是一些主要实现的快速概述:

安全

  • nptl - pthread_cond_destroy()将返回EBUSY,如果有条件仍然阻止线程。销毁责任将传递给未解锁信号的线程。
  • 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()。这有一个known race condition

Oddballs

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

<强> 修改

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

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

当您致电pthread_cond_broadcast()时,您无法获取相关的互斥锁。等待条件变量的线程将按顺序执行,而每个线程都会串行获取相关的互斥锁。因为您的服务员可能会互相阻止,所以您的广播线程可能会继续执行,而服务员仍然在互联网上pthread_cond_wait()被阻止(但不等待该条件)。


编辑2

  

[...]期望取消映射在相同的上下文中有效是否合理?销毁是否有效?

我不认为这是基于编辑1中的推理的合理期望。如果您被禁止使用pthread_cond_destroy()

,则肯定需要进行额外的同步

答案 2 :(得分:0)

评论(不回答):

这是你的想法吗?

全局:

// protected by 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);
{ // locked region
    about_to_pthread_cond_wait = true;
    while (condition_waited_on) {
        // pthread_cond_wait (&m, &c) is decomposed here:
        __pthread_mutex_cond_wait_then_unlock (&m, &c);
            // unlocked region
        pthread_mutex_lock (&m);
    }
}
pthread_mutex_unlock (&m);

主题B:

for (bool break_loop = false; !break_loop;) {
    pthread_mutex_lock (&m);
    { // locked region
        condition_waited_on = true;

        if (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的信号,然后解锁互斥锁,然后进入睡眠状态。

如果简历中有__pthread_mutex_cond_wait_then_unlockpthread_cond_signal必须锁定的内部互斥锁,那么我认为__pthread_mutex_cond_wait_then_unlock会这样做:

pthread_mutex_lock (&c.int_mutex);
{ // locked region for c.int_state
    __register_wakeup_cond (&c.int_state);
    pthread_mutex_unlock (&m);
}
pthread_mutex_unlock (&c.int_mutex);
// will not touch c.int_state any more 

__sleep_until_registered_wakeups ();

pthread_cond_signal确实:

pthread_mutex_lock (&c.int_mutex);
{ // locked region for CV internal state
    __wakeup_registered (&c.int_state);
}
pthread_mutex_unlock (&c.int_mutex);

然后只有在pthread_cond_destroy使用__pthread_mutex_cond_wait_then_unlock后才会调用c.int_state