c++ 挂起pthreads而不使用条件

voj3qocg  于 2023-07-01  发布在  其他
关注(0)|答案(7)|浏览(125)

我想挂起pthreads,但显然没有pthread_suspend这样的函数。我在某个地方读到过关于使用互斥锁和条件挂起pthreads的内容,并如下所示使用它:

#include <pthread.h>

class PThread {
public:
pthread_t myPthread;
pthread_mutex_t m_SuspendMutex;
pthread_cond_t m_ResumeCond;

void start() {
pthread_create(&myPthread, NULL, threadRun, (void*)this );
}

Thread() { }

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

void resume() {
pthread_cond_signal(&m_ResumeCond);
}
};

但是我不明白为什么我们需要互斥和条件来挂起和恢复一个pthread。是否可以在不使用条件的情况下暂停和恢复它?

ifsvaxew

ifsvaxew1#

您的代码不正确-pthread_cond_wait()要求在您调用它时已经锁定互斥体:

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

但是,这仍然是错误的。一个线程可以在任何时候从pthread_cond_wait()中唤醒,* 不一定 * 只有当它被发送信号时。这意味着您需要将pthread_cond_wait()与某个共享状态配对,该状态对线程真正等待的条件进行编码-在最简单的情况下,您可以只使用一个标志变量。pthread_cond_signal()用于告诉线程它应该唤醒并重新检查共享状态。将此应用于您的实现:

class PThread {
    public:

    pthread_t myPthread;
    bool suspended;
    pthread_mutex_t m_SuspendMutex;
    pthread_cond_t m_ResumeCond;

    void start() {
        suspended = false;
        pthread_create(&myPthread, NULL, threadRun, (void*)this );
    }

    Thread() { }

    void suspendMe() {
        pthread_mutex_lock(&m_SuspendMutex);
        suspended = true;
        do {
            pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
        } while (suspended);
        pthread_mutex_unlock(&m_SuspendMutex);
    }

    void resume() {
        /* The shared state 'suspended' must be updated with the mutex held. */
        pthread_mutex_lock(&m_SuspendMutex);
        suspended = false;
        pthread_cond_signal(&m_ResumeCond);
        pthread_mutex_unlock(&m_SuspendMutex);
    }
};

提供互斥体的原因是为了保护共享状态并避免竞争条件-pthread_cond_wait()函数实际上在等待时执行原子解锁和等待,这允许避免“错过唤醒”。例如,在这段代码中,互斥体防止suspendedsuspended = true;pthread_cond_wait()行之间变为false。

unhi4e5o

unhi4e5o2#

如果一个线程没有等待某种条件,你怎么能“信号”它继续。它不能停止执行任何东西,然后神奇地重新开始,所以它等待一个条件。
具体来说,在pthreads中,恢复线程的方法实际上是使用条件变量。没有可用的API以任何其他方式挂起/恢复线程。等待pthread_cond_wait是廉价的,它会阻塞直到条件被发出信号,而不是使用(多?您使用条件来通知线程唤醒,并且需要互斥体来保护在唤醒时对条件变量和线程中的代码的访问。

1wnzp6jl

1wnzp6jl3#

条件总是与互斥体相关联。通常,线程会休眠,因为它在等待状态的改变来指示它有工作要做;你需要互斥体来保护对那个状态的访问,并需要条件来发出改变的信号。
唤醒一个线程而不告诉它你为什么唤醒它是一件有点奇怪的事情,所以没有特殊的方法来做;实现这一点的唯一方法是使用普通机制,但是没有共享状态。
如果出于某种原因,您希望从另一个线程挂起和恢复该线程,而不考虑要它完成的工作,那么您可以使用pthread_kill向它发送SIGSTOPSIGCONT信号;我从来没有尝试过这样做,所以我不知道它是否支持。

inkz8wg9

inkz8wg94#

互斥锁用于确保独占访问,而条件变量用于根据事件同步线程。
我们需要互斥体来确保条件变量不会在无限等待中结束。需要记住的一点是,锁和解锁的互斥操作保证是原子的,但条件变量不需要是原子的。也就是说,当条件变量wait为一半时,线程可以被调度出去。
考虑以下情况,条件变量没有Mutex。

线程1

1)执行某些操作
2)等待条件变量
3)继续操作

线程2

1)执行某些操作
2)向条件变量发送信号
3)继续操作
在线程1中,步骤2不保证是原子的。如果线程1在完成步骤1之前被调度程序推出RUNNING状态。现在线程2开始执行并向条件变量发送信号。当线程1恢复执行时,它将完成剩余的低级指令并开始等待。线程1在无限等待中结束,因为条件变量的信号甚至在等待之前发生。
所以正确的使用方法是(我相信问题中提到的代码没有达到预期的效果)

线程1:-

1)做工作直到一定条件必须发生的点(如“计数”必须达到指定值)
2)锁关联互斥体
3)调用pthread_cond_wait()对来自Thread 1的信号执行阻塞等待。(注意,对pthread_cond_wait()的调用自动地、原子地解锁关联的互斥变量,以便它可以被Thread 2使用)
4)一有信号,就醒过来。互斥体是自动和原子锁定的。
5)显式解锁互斥体

Thread2

1)做工作
2)锁关联互斥体
3)更改Thread 1正在等待的全局变量的值。
4)检查全局Thread 1等待变量的值。如果满足所需条件,则向Thread 1发送信号。
5)解锁互斥锁。继续

2sbarzqh

2sbarzqh5#

看起来没有任何Linux替代Windows API SuspendThread函数。在线程过程中不注入任何代码就不可能暂停Linux线程。

bf1o4zei

bf1o4zei6#

2010年6月29日由“caf”回复的代码是正确的,可以很好地同步两个协作线程。但是,suspendMe例程中的pthread_mutex_unlock是多余的,因为pthread_cond_wait嵌入了unlock。(pthread_mutex_unlock实际上返回一个错误,在大多数情况下这是无害的,但明智的代码平衡了每个锁与解锁。)代码应该是:

void suspendMe() {
    pthread_mutex_lock(&m_SuspendMutex);
    suspended = true;
    do {
// note pthread_cond_wait() function performs an atomic-unlock-and-wait
        pthread_cond_wait(&m_ResumeCond, &m_SuspendMutex);
    } while (suspended);
}
ql3eal8s

ql3eal8s7#

更重要的是-你最终想做什么?- 我想答案不是“暂停线程”。可能是你的程序设计有问题。

相关问题