什么时候可以使用 cond var 来同步其自身的销毁/取消映射?

发布于 2024-12-07 05:33:15 字数 538 浏览 2 评论 0原文

根据 POSIX 的规定,

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

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

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

  1. 在成功发出信号后,在等待线程或信号线程中,当恰好一个线程被阻塞时在条件变量上。
  2. 成功广播后,在任何等待线程或广播线程中立即进行。

当然,这假设不会有更多的等待者到达,并且之后不会执行更多的信号,如果使用 pthread_cond_destroy,应用程序负责保证这一点。

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

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

According to POSIX,

It shall be safe to destroy an initialized condition variable upon which no threads are currently blocked.

Further, the signal and broadcast operations are specified to unblock one/all threads blocked on the condition variable.

Thus, it seems to me the following forms of self-synchronized destruction should be valid, i.e. calling pthread_cond_destroy:

  1. Immediately after a successful signal, in either the waiting or the signaling thread, when exactly one thread is blocked on the cond var.
  2. Immediately after a successful broadcast, in either any waiting thread or the broadcasting thread.

Of course this assumes no further waiters will arrive and no further signals shall be performed afterwards, which the application is responsible for guaranteeing if using pthread_cond_destroy.

Am I correct that destruction is valid in these situations? And are there other self-synchronized destruction scenarios to be aware of with condition variables?

Finally, for process-shared cond vars where unmapping the shared mapping without destruction might make sense, is it reasonable to expect unmapping to be valid in the same contexts destruction would be valid, or must further synchronization be performed if multiple threads in the same process (address space) are using the same mapping and want to unmap it in one of the above contexts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

扬花落满肩 2024-12-14 05:33:15

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

因此,我认为从您描述的场景来看,只有一种情况是有效的,即单独阻塞的线程或进程在被唤醒后破坏条件的情况。

No, I don't think that most of your assumptions are correct. Returning from pthread_cond_signal or pthread_cond_broadcast does not indicate that any of the threads are yet "unblocked" from the condition variable, i.e that the threads that are to be unblocked don't need access to that variable anymore. The standard only says "shall unblock" and not "on successful return from this call they will be unblocked". The later would be very restrictive for implementations, so there is probably a good reason that this is formulated as it is.

So I think from the scenarios you describe only one is valid, namely the case were the solely blocked thread or process destroys the condition after being woken up.

旧人九事 2024-12-14 05:33:15

评论(不是回答):

这是你的想法吗?

全局:

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

如果 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 后调用。

Comment (not answer):

Is that what you have in mind?

Global:

// protected by m:
pthread_mutex_t m;
pthread_cond_t c;
bool about_to_pthread_cond_wait = false;
bool condition_waited_on = false;

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

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

EDIT:

I assume pthread_cond_wait (&m, &c); does:

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

__pthread_mutex_cond_wait_then_unlock will being monitoring the signals to the CV, then unlock the mutex, then go to sleep.

If the CV has an internal mutex that __pthread_mutex_cond_wait_then_unlock and pthread_cond_signal must lock internaly, then I assume __pthread_mutex_cond_wait_then_unlock does:

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

and pthread_cond_signal does:

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

Then pthread_cond_destroy will only be called after __pthread_mutex_cond_wait_then_unlock has finished using c.int_state.

深巷少女 2024-12-14 05:33:15

虽然我同意您对此语言的解释(以及 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()。这有一个已知的竞争条件

Oddballs

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

编辑

如果我正确地阅读了您的评论,主要问题是pthread_cond_wait()是否可以之前访问条件变量 它返回,但之后它被解锁。答案是。该例程假定其参数仍然有效。

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

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


编辑 2

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

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

While I agree with your interpretation (and that of the Open POSIX test suite) of this language, usage will be implementation dependent. As such, here is a quick rundown of some of the major implementations:

Safe

  • nptl - pthread_cond_destroy() will return EBUSY if there are threads still blocked on the condition. Destruction responsibility will pass to the threads that are signaled by not unblocked.
  • pthread-win32 MSVC - pthread_cond_destroy() will return EBUSY if there are threads still blocked on the condition. Threads that are signaled but not unblocked will be executed before pthread_cond_destroy() returns control to the application.

Safe but blocking

  • Darwin libc-391 - pthread_cond_destroy() will return EBUSY if there are threads still blocked on the condition. No provisions are made for blocked but signaled threads.
  • dietlibc 0.27 - pthread_cond_destroy() will return EBUSY if there are threads still blocked on the condition. No provisions are made for blocked but signaled threads.

Possibly not safe

  • Android - Depends on system implementation of __futex_wake_ex to be synchronous. Thus pthread_cond_broadcast() must block until all threads have woken (but not released their mutex).
  • various win32 implementations - Many rely on the PulseEvent() function to implement pthread_cond_broadcast(). This has a known race condition

Oddballs

  • OSKit 0.9 - Safe but returns EINVAL if pthread_cond_destroy() is called on a condition variable that is still referenced

Edit

The major issue, if I read your comments correctly is whether the pthread_cond_wait() can access the condition variable before it returns but after it is unblocked. And the answer is yes. The routine assumes that its arguments will remain valid.

This means that after broadcasting, your thread cannot assume that the condition variable is unused by other threads.

When you call pthread_cond_broadcast(), you do not acquire the associated mutex lock. While the threads waiting on your condition variable will execute sequentially, each acquiring the associated mutex in series. Because your waiters may block each other, your broadcasting thread may continue executing while waiters are still in pthread_cond_wait() blocked on the mutex (but not waiting for the condition).


Edit 2

[...]is it reasonable to expect unmapping to be valid in the same contexts destruction would be valid?

I don't think that this is a reasonable expectation based on the reasoning in Edit 1. Additional synchronization would definitely be required if you are precluded from using pthread_cond_destroy()

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文