线程调度程序模拟:唤醒和睡眠Pthread的正确方法

Thread Scheduler Simulation: Correct Way to Wake Up and Sleep a Pthread

本文关键字:Pthread 方法 模拟 调度程序 唤醒 线程      更新时间:2023-10-16

我正在尝试使用"先到先得"策略设计自己的线程调度程序,我不确定让线程休眠和唤醒它们的方式是否正确。我使用的是C++和Pthreads库。

我的想法是:

  • 主线程实例化一个工作线程
  • 从工作线程调用单独的schedule()函数,表示应该调度调用线程。传入一个arrival timeidremaining time
  • schedule()中,创建我自己的Thread对象,该对象存储特定线程的arrival timeidremaining time属性(这些是我创建的属性)。Thread对象也有自己的条件变量
  • 每次调用schedule()函数时,都会创建一个Thread对象并将其添加到队列的后面
  • 一旦Thread对象被添加到队列中,调用schedule()的线程就应该等待其相应的条件变量
  • 然后,应该用信号通知队列前面的Thread对象的条件变量,指示它应该运行。所有其他线程都应该等待它们各自的Thread对象中的条件变量

示例queue[0]queue[1]queue[2]queue[3]queue[4]中存在5个Thread对象。由queue[0]表示的线程应该正在运行,由queue[1]queue[2]queue[3]queue[4]表示的线程应当等待它们各自的条件变量。一旦队列[0]完成执行,它将从队列中删除,所有的Thread对象都将向前移动,并且新的queue[0]将被通知运行。如果我现在从一个新的工作线程调用schedule(),那么应该在queue[4]处创建并添加一个新Thread对象。调用线程应该在queue[4]上等待。

为了测试这个设计,我写了一个例子。我省略了arrival timeidremaining time字段,因为它们在这一点上并不重要。以下是示例代码:

#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
using namespace std;
class Thread {
    public:
            pthread_cond_t conVar;
};
vector<Thread> queue;
pthread_mutex_t lock;
void schedule() {
    pthread_mutex_lock(&lock);
    cout << "Thread 1 locks the mutexn";
    queue.push_back(first);
    pthread_cond_wait(&(queue.back()).conVar,&lock);
}
void *worker(void *arg) {
    Thread first;
    cout << "Thread 1 adding to queue. Going for the wait...n";
    schedule();
    cout << "Got out of the wait. Let's do some workn";
    for(int i = 0; i < 20; i++)
            cout << i << " ";
    cout << "n";
    pthread_exit(NULL);
}
int main() {

    vector<Thread> queue;
    pthread_t a;
    pthread_create(&a,NULL,worker,NULL);
    cout << "Sleeping in the main thread for a bit....n";
    sleep(1);
    cout << "Now let's signal the Thread object in the queuen";
    int result = pthread_mutex_trylock(&lock);
    if(result != 0)
            sleep(3);
    pthread_cond_signal(&(queue.front()).conVar);
    pthread_mutex_unlock(&lock);
    pthread_join(a,NULL);

    return 0;
}

我已经尝试过几次这个示例代码,主线程总是首先执行,并尝试向队列的前面发出信号。工作线程从来没有及时得到队列来插入Thread对象,我一直得到一个segfault,因为主线程试图用信号通知一个不存在的条件变量。

我的问题是:作为调度算法的一部分,这种设计是让线程休眠并唤醒它们的有效方法吗?还是主线程总是先执行,然后尝试发出空队列的信号?

"main"线程只是一个碰巧由操作系统加载程序而不是用户代码创建的线程。它在任何方面都不"特别"。

一个问题是,您正试图将线程与睡眠调用同步。这不会有好的结局。

如果你想试试这个,先用另一种方式发信号。将condvar传递给worker,并在main中等待它。当worker将自己插入队列时,它可以向condvar发出信号,以便main可以继续。