在linux CFS调度下的C/ c++多线程场景中出现意外结果

Unexpected result in multithreading scenario in C/C++ under linux CFS schedualar

本文关键字:结果 意外 多线程 c++ 调度 CFS linux      更新时间:2023-10-16

我在主线程内创建了多个线程(4个线程)。虽然每个线程执行相同的函数,线程的调度与预期的不一样。根据我对操作系统的理解,linux的CFS调度器将分配"t"虚拟运行时间量,在该时间量到期时,CPU将从当前线程中抢占分配给下一个线程。通过这种方式,每个线程将获得公平的CPU份额。我得到的和我期望的不一样。

我希望所有线程(线程1-4,主线程)将在同一线程(任何)下一次获得CPU之前获得CPU。

期望输出

foo3->1->Time Now: 00:17:45.346225000

foo3->1->Time Now: 00:17:45.348818000

foo4->1->Time Now: 00:17:45.350216000

foo4-->1-->Time Now: 00:17:45.352800000

main is running -> 1->Time Now: 00:17:45.355803000

main is running -> 1->Time Now: 00:17:45.360606000

foo2->1->Time Now: 00:17:45.345305000

foo2->1->Time Now: 00:17:45.361666000

foo1-->1-->Time Now: 00:17:45.354203000

foo1-->1-->Time Now: 00:17:45.362696000

foo1->2->Time Now: 00:17:45.362716000//foo1线程第二次获得CPU

foo1-->2-->Time Now: 00:17:45.365306000

但是我得到

foo3->1->Time Now: 00:17:45.346225000

foo3->1->Time Now: 00:17:45.348818000

foo4->1->Time Now: 00:17:45.350216000

foo4-->1-->Time Now: 00:17:45.352800000

main is running -> 1->Time Now: 00:17:45.355803000

main is running -> 1->Time Now: 00:17:45.360606000

foo3->2->Time Now: 00:17:45.345305000////foo3线程在CFS调度其他线程之前第二次意外获得CPU

foo3->2->Time Now: 00:17:45.361666000

foo1-->1-->Time Now: 00:17:45.354203000

foo1-->1-->Time Now: 00:17:45.362696000

foo1->2->Time Now: 00:17:45.362716000

foo1-->2-->Time Now: 00:17:45.365306000

这是我的程序(thread_multi.cpp)

#include <pthread.h>
#include <stdio.h>
#include "boost/date_time/posix_time/posix_time.hpp"
#include <iostream>
#include <cstdlib>
#include <fstream>
#define NUM_THREADS  4
using namespace std;
std::string now_str()
{
    // Get current time from the clock, using microseconds resolution
    const boost::posix_time::ptime now = 
        boost::posix_time::microsec_clock::local_time();
    // Get the time offset in current day
    const boost::posix_time::time_duration td = now.time_of_day();
    const long hours        = td.hours();
    const long minutes      = td.minutes();
    const long seconds      = td.seconds();

    const long nanoseconds = td.total_nanoseconds() - ((hours * 3600 + minutes * 60 + seconds) * 1000000000);
    char buf[40];
    sprintf(buf, "Time Now : %02ld:%02ld:%02ld.%03ld", hours, minutes, seconds, nanoseconds);
    return buf;
}

/* This is our thread function.  It is like main(), but for a thread*/
void *threadFunc(void *arg)
{
    char *str;
    int i = 0;
    str=(char*)arg;
    while(i < 100 )
    {
        ++i;
        ofstream myfile ("example.txt", ios::out | ios::app | ios::binary);
        if (myfile.is_open())
          {
            myfile << str <<"-->"<<i<<"--->" <<now_str() <<" n";
          }
          else cout << "Unable to open file";
        // generate delay 
        for(volatile int k=0;k<1000000;k++);

        if (myfile.is_open())
          {
            myfile << str <<"-->"<<i<<"--->" <<now_str() <<"nn";
            myfile.close();
          }
          else cout << "Unable to open file";
    }

}
int main(void)
{
    pthread_t pth[NUM_THREADS]; // this is our thread identifier
    int i = 0;
    pthread_create(&pth[0],NULL, threadFunc,  (void *) "foo1");
    pthread_create(&pth[1],NULL,  threadFunc, (void *) "foo2");
    pthread_create(&pth[2],NULL, threadFunc,  (void *) "foo3");
    pthread_create(&pth[3],NULL,  threadFunc, (void *) "foo4");

std::cout <<".............n" <<now_str() << 'n';      
    while(i < 100)
    {
        for(int k=0;k<1000000;k++);
        ofstream myfile ("example.txt", ios::out | ios::app | ios::binary);
          if (myfile.is_open())
          {
            myfile << "main is running ---> "<< i <<"--->"<<now_str() <<'n';
            myfile.close();
          }
          else cout << "Unable to open file";

        ++i;
    }
//  printf("main waiting for thread to terminate...n");
    for(int k=0;k<4;k++)
    pthread_join(pth[k],NULL);
std::cout <<".............n" <<now_str() << 'n';      
    return 0;
}

这里是完全公平调度细节

内核。Sched_min_granularity_ns = 100000内核。Sched_wakeup_granularity_ns = 25000 kernel。sched_latency_ns =1000000

根据sched_min_granularity_ns值,任何任务都将在该最小时间内执行,如果任务需要的时间超过该最小时间,则计算时间片,并在该时间片内执行每个任务。

这里时间片是用公式计算的,

time slice =(每个任务的权重/下所有任务的总权重)CFS运行队列x sched_latency_ns

谁能解释为什么我得到这些结果调度????任何帮助理解输出将是非常感激的。提前谢谢你。

我在linux下使用gcc。

EDIT:

如果我改变这个循环

(int k = 0; k<100000; k + +);

(int k = 0; k<10000; k + +);

则有时线程1连续获得CPU 10次,线程2连续获得CPU 5次,线程3连续获得CPU 5次,主线程连续获得CPU 2次,线程4连续获得CPU 7次。看起来不同的线程是随机被抢占的。

这些随机的没有连续的CPU分配给不同的线程的线索。

CPU分配一些时间来执行每个线程。为什么每个线程不做相同数量的打印?

我将在一个示例中解释这一点:

承认你的计算机每秒钟能发出100条指令承认打印1张相当于使用了25条指令承认每个线程有1ns的工作时间

现在你必须明白计算机中的所有程序都在消耗100条可用指令

如果你的线程想要打印一些东西,有100条指令可用,它可以打印4句话。如果你的线程想要打印一些东西,有40条指令可用,它可以打印1句。只有40条指令,因为其他程序正在使用指令。

你明白吗?

如果你有任何问题,欢迎提问。:)