【问题标题】:using sched_yield to control thread execution使用 sched_yield 控制线程执行
【发布时间】:2015-11-02 21:59:11
【问题描述】:

我有 2 个线程:将“重新打印”用户输入语句的元音和辅音。元音线程将打印以元音开头的单词,辅音线程将打印以辅音开头的单词...我正在尝试使用 sched_yield() 以与用户输入相同的顺序输出... 因此,如果用户输入是:大家好,辅音线程将打印 hi 和元音将打印所有,按那个顺序.. 但我似乎遗漏了一些东西,因为我没有得到相同的顺序.. 你能帮忙吗...

void *vowels( void *s )
{
    for(int i = 1; i < noOfTokens; i++){
        string str = tokens[i];
        size_t found = str.find_first_of(vowelList);
        if(found == 0){
            printf("vows %s\n", tokens[i]);
        }
        else {
            sched_yield();
      } 
  }
  pthread_exit(0);
}


/* the cons thread should print all words starting with a consonant.  */
void *consonants( void *s )
{
    for(int j = 1; j < noOfTokens; j++){
        string str = tokens[j];
        size_t found = str.find_first_of(vowelList);
        if(found != 0){
            printf("cons %s\n", tokens[j]);
        }
        else {
            sched_yield();
      } 
  }
  pthread_exit(0);

}

【问题讨论】:

  • 如果没有一些线程间通信,这将永远无法工作。 yield 是给调度程序的一条消息,基本上是说“我现在不需要更多时间来运行,继续给你喜欢的任何线程时间,包括我”。研究使用信号量或互斥体。
  • 除非准备运行的线程比你拥有的内核多,否则你的线程将无法让步,所以sched_yield 不会做任何事情。

标签: c++ scheduling


【解决方案1】:

正如 Kenney 所说,单独使用 yield 不会帮助您同步这两个线程。为此,您必须使用互斥锁或其他一些同步原语。话虽如此,我不禁注意到您的问题可以在condition variable 的帮助下优雅地解决。我选择使用c++11std::thread,以及std::mutexstd::condition_variable

我稍微简化了你的问题,我的目标是打印偶数和奇数,按照输入的顺序购买两个不同的线程(一个线程负责偶数,另一个负责奇数)。一种可能的解决方案可能是:

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex m;
std::condition_variable cv;
unsigned int index = 0;

void ProcessEvenNumbers(void *p_array)
{
    std::vector<int>& buffer(*reinterpret_cast<std::vector<int>*>(p_array));
    std::unique_lock<std::mutex> lock(m);

    while (index < buffer.size())
    {
        if (buffer[index] % 2 == 0)
        {
            std::cout << "thread_1: " << buffer[index] << std::endl;
            ++index;
        }
        else
        {
            cv.wait(lock);
        }
    }
}

void ProcessOddNumbers(void *p_array)
{
    std::vector<int>& buffer(*reinterpret_cast<std::vector<int>*>(p_array));
    std::unique_lock<std::mutex> lock(m);

    while(index < buffer.size())
    {
        if (buffer[index] % 2 != 0)
        {
            std::cout << "thread_2: " << buffer[index] << std::endl;
            ++index;
        }
        else
        {
            lock.unlock();
            cv.notify_one();
            std::this_thread::sleep_for(std::chrono::microseconds(1));
            lock.lock();
        }
    }

    cv.notify_one();
}

int main()
{
    std::vector<int> buffer{ 1, 3, 24, 5, 100, -23, -2, -2, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14 };
    std::thread thread_2(ProcessOddNumbers, &buffer);
    std::thread thread_1(ProcessEvenNumbers, &buffer);

    thread_1.join();
    thread_2.join();

    return 0;
}

处理偶数的线程(ProcessEvenNumbers())在遇到奇数时使用条件变量阻塞自己。处理奇数的线程 (ProcessOddNumbers()) 在遇到偶数时使用notify_one() 解除对另一个线程的阻塞,并通过尝试重新锁定互斥锁(此时已被其他线程锁定)来阻塞自己。

std::this_thread::sleep_for() 非常关键,因为它强制进行上下文切换,允许thread_1thread_2 发出条件变量信号后锁定互斥锁。

P.S.线程运行的顺序无关紧要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多