C++ 暂停和恢复 pthread 的最佳解决方案是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13662689/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:36:30  来源:igfitidea点击:

What is the best solution to pause and resume pthreads?

c++pthreadsposix

提问by Chef Pharaoh

I've found the following topic (here) about pthreads but there are many good solutions.

我发现了以下关于 pthreads 的主题(here),但有很多很好的解决方案。

I wanted to know if the following piece of code is valid and if so, why the same lock is used to call pthread_cond_wait as well as access it and then unlocked right away:

我想知道以下代码段是否有效,如果有效,为什么使用相同的锁来调用 pthread_cond_wait 以及访问它然后立即解锁:

void suspendMe()
{
    pthread_mutex_lock(&m_SuspendMutex);
    pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
    pthread_mutex_unlock(&m_SuspendMutex);
}

Would it not be better to use 2 separate mutexes here, or is this the correct way to suspend a pthread??

在这里使用 2 个单独的互斥锁不是更好,还是这是挂起 pthread 的正确方法?

Thanks in advance!

提前致谢!

EDIT:

编辑:

Awesome replies, thanks all. Just one more related question. Since I want to resume a thread separately in another function, would this be more proper in resuming it?

很棒的回复,谢谢大家。还有一个相关的问题。既然我想在另一个函数中单独恢复一个线程,那么恢复它会更合适吗?

void suspendMe()
{
    pthread_mutex_lock(&m_SuspendMutex);
    pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
}
void resumeMe()
{
    pthread_cond_signal(&m_ResumeCond);
    pthread_mutex_unlock(&m_SuspendMutex);
}

Thanks again everyone!! :~)

再次感谢大家!!:~)

采纳答案by David Schwartz

Actually, this code isn't thread safe. The mutex isn't actually protecting anything, leaving the implied predicate vulnerable to race conditions.

实际上,这段代码不是线程安全的。互斥锁实际上并没有保护任何东西,使得隐含的谓词容易受到竞争条件的影响。

Look at this code -- what is the mutex protecting? What protects the suspend/resume state?

看看这段代码——互斥锁保护什么?什么保护挂起/恢复状态?

void suspendMe()
{
    pthread_mutex_lock(&m_SuspendMutex);
    pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
}
void resumeMe()
{
    pthread_cond_signal(&m_ResumeCond);
    pthread_mutex_unlock(&m_SuspendMutex);
}

This is correct:

这是对的:

void suspendMe()
{ // tell the thread to suspend
    pthread_mutex_lock(&m_SuspendMutex);
    m_SuspendFlag = 1;
    pthread_mutex_unlock(&m_SuspendMutex);
}
void resumeMe()
{ // tell the thread to resume
    pthread_mutex_lock(&m_SuspendMutex);
    m_SuspendFlag = 0;
    phtread_cond_broadcast(&m_ResumeCond);
    pthread_mutex_unlock(&m_SuspendMutex);
}
void checkSuspend()
{ // if suspended, suspend until resumed
    pthread_mutex_lock(&m_SuspendMutex);
    while (m_SuspendFlag != 0) pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
    pthread_mutex_unlock(&m_SuspendMutex);
}

The thread should call checkSuspendat safe points where it can be suspended. Other threads can call suspendMeand resumeMeto suspend/resume the thread.

线程应该checkSuspend在可以挂起的安全点调用。其他线程可以调用suspendMeresumeMe挂起/恢复线程。

Notice that now the mutex protects the m_SuspendFlagvariable, ensuring that the thread is told to suspend, told to resume, and checks whether it should suspend or stay suspended under protection, making the code thread-safe.

请注意,现在互斥锁保护m_SuspendFlag变量,确保线程被告知挂起、被告知恢复,并检查它是否应该在保护下挂起或保持挂起,从而使代码线程安全。

Would it not be better to use 2 separate mutexes here, or is this the correct way to suspend a pthread??

在这里使用 2 个单独的互斥锁不是更好,还是这是挂起 pthread 的正确方法?

Using two mutexes would defeat the entire point of condition variables. The whole mechanism by which they work is that you can check whether there is something you should wait for and then atomically wait for it without either holding the lock while you wait or having to release the lock and then wait. If you hold the lock while you wait, how can any other thread change the state? And if you release the lock and then wait, what happens if you miss the change in state?

使用两个互斥体会破坏条件变量的整个点。它们工作的整个机制是你可以检查是否有你应该等待的东西,然后原子地等待它,而不必在等待时持有锁或必须释放锁然后等待。如果您在等待时持有锁,其他线程如何更改状态?如果您释放锁然后等待,如果您错过状态更改会发生什么?

By the way, it almost never makes sense to pause or resume a thread. If you feel like you need to pause a thread from the outside, that just indicates that you coded the thread to do something you didn't actually want it to do. Questions about pausing or resuming threads often indicate an incorrect mental model of thread programming. A thread might need to wait for something, but it shouldn't be "paused" from the outside because it should already know by its own coding when it shouldn't do some particular bit of work.

顺便说一句,暂停或恢复线程几乎没有任何意义。如果您觉得需要从外部暂停一个线程,那只是表明您对该线程进行了编码,以执行您实际上并不希望它执行的操作。有关暂停或恢复线程的问题通常表明线程编程的心理模型不正确。一个线程可能需要等待一些东西,但它不应该从外部“暂停”,因为它应该已经通过自己的编码知道什么时候不应该做一些特定的工作。

回答by ybungalobill

This is the correct way. pthread_cond_waitunlocksm_SuspendMutex, then waits on m_ResumeCondand then locks m_SuspendMutexagain before returning.

这是正确的方法。pthread_cond_wait解锁m_SuspendMutex,然后等待m_ResumeCond,然后m_SuspendMutex在返回之前再次锁定。

The reason it works this way is because condition variables are used to signal a change of some state, and since this state is shared it must be locked while some thread is accessing it. E.g. consider implementing a queue of events:

它以这种方式工作的原因是因为条件变量用于表示某些状态的变化,并且由于该状态是共享的,因此在某些线程访问它时必须锁定它。例如,考虑实现一个事件队列:

T get_item()
{
    pthread_mutex_lock(&mutex);
    while(qu.empty())
        pthread_cond_wait(&cond, &mutex);
    T ret = qu.front();
    qu.pop();
    pthread_mutex_unlock(&mutex);
    return ret; // we got an item from a queue
}

void add_item(T x)
{
    pthread_mutex_lock(&mutex);
    qu.push(x);
    pthread_mutex_unlock(&mutex);
    pthread_cond_signal(&cond);
}

Note that:

注意:

  1. All the access to the queue quis synchronized using the mutex.
  2. When we wait on the condition variable, we must unlock the mutexin order to allow the other threads to add items to the queue, and when it have been changed we must lock the mutexagain to actually inspect the queue. This is exactly what pthread_cond_signaldoes.
  1. 对队列的所有访问qu都使用mutex.
  2. 当我们等待条件变量时,我们必须解锁mutex以允许其他线程向队列添加项目,并且当它被更改时,我们必须mutex再次锁定以实际检查队列。这正是pthread_cond_signal它的作用。

回答by Martin York

I wanted to know if the following piece of code is valid

我想知道以下代码是否有效

Yes.

是的。

and if so, why the same lock is used to call pthread_cond_wait as well as access it and then unlocked right away:

如果是这样,为什么使用相同的锁来调用 pthread_cond_wait 以及访问它然后立即解锁:

The pthread_cond_wait()requires a locked mutex. This is because of the way condition varaibles are used. Normally they are used like this:

pthread_cond_wait()需要一个锁定的互斥。这是因为条件变量的使用方式。通常它们是这样使用的:

pthread_mutex_lock(&m_SuspendMutex);
while (!ready())
{
    pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
}

// Modify the resources protexted by the lock.
pthread_mutex_unlock(&m_SuspendMutex);

So you acquire the lock saying you want to modify the resources protected by the lock. But if the object is not in a ready()state then you suspend your thread with pthread_cond_wait()which suspends the thread and unlocks the mutex (thus allowing other threads to aquire the lock and potentially transform the object into a ready()state).

所以你获得了锁,说你想修改受锁保护的资源。但是,如果对象不处于ready()状态,那么您将挂起线程,pthread_cond_wait()从而挂起线程并解锁互斥锁(从而允许其他线程获取锁并可能将对象转换为ready()状态)。

When the ready state is achieved the m_ResumeCondis signalled and a waiting thread is released from suspension. But before it is allowed to exit pthread_cond_wait()it must reaquire the lock on m_SuspendMutexto make sure it is the only thread modifying the resources protected by the mutex.

当达到就绪状态时,m_ResumeCond会发出信号并从暂停中释放等待线程。但是在允许退出之前,pthread_cond_wait()它必须重新获得锁定m_SuspendMutex以确保它是唯一修改受互斥锁保护的资源的线程。

To make sure the above is done correctly in an atomic fashion (the unlock/suspend/resume/lock) must by done by pthread_cond_wait().

为确保上述操作以原子方式(解锁/挂起/恢复/锁定)正确完成,必须由 pthread_cond_wait().

Would it not be better to use 2 separate mutexes here

在这里使用 2 个单独的互斥锁不是更好吗

No.

不。

or is this the correct way to suspend a pthread??

或者这是挂起 pthread 的正确方法?

As good as any other I suppose.

和我想的任何其他一样好。