【问题标题】:Unexpected result in multithreading scenario in C/C++ under linux CFS schedualarlinux CFS schedualar 下 C/C++ 中多线程场景的意外结果
【发布时间】:2014-03-18 19:12:31
【问题描述】:

我在主线程中创建了多个线程(4 个线程)。虽然每个线程都执行相同的功能, 线程的调度与预期的不同。根据我对操作系统的理解,linux CFS 调度程序将 分配“t”虚拟运行时间量,并且在该时间量到期时,CPU被当前线程抢占,并且 分配给下一个线程。通过这种方式,每个线程都将获得公平的 CPU 份额。我得到的不是预期的。

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

预期输出是

foo3-->1--->现在时间:00:17:45.346225000

foo3-->1--->现在时间:00:17:45.348818000

foo4-->1--->现在时间:00:17:45.350216000

foo4-->1--->现在时间:00:17:45.352800000

main 正在运行 ---> 1--->现在时间:00:17:45.355803000

main 正在运行 ---> 1--->现在时间:00:17:45.360606000

foo2-->1--->现在时间:00:17:45.345305000

foo2-->1--->现在时间:00:17:45.361666000

foo1-->1--->现在时间:00:17:45.354203000

foo1-->1--->现在时间:00:17:45.362696000

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

foo1-->2--->现在时间:00:17:45.365306000

但我得到了

foo3-->1--->现在时间:00:17:45.346225000

foo3-->1--->现在时间:00:17:45.348818000

foo4-->1--->现在时间:00:17:45.350216000

foo4-->1--->现在时间:00:17:45.352800000

main 正在运行 ---> 1--->现在时间:00:17:45.355803000

main 正在运行 ---> 1--->现在时间:00:17:45.360606000

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

foo3-->2--->现在时间:00:17:45.361666000

foo1-->1--->现在时间:00:17:45.354203000

foo1-->1--->现在时间:00:17:45.362696000

foo1-->2--->现在时间:00:17:45.362716000

foo1-->2--->现在时间: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() <<"\n\n";
            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;
}

这是完全公平的调度程序详细信息

kernel.sched_min_granularity_ns = 100000 kernel.sched_wakeup_granularity_ns = 25000 kernel.sched_latency_ns = 1000000

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

这里使用公式计算时间片,

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

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

我在linux下使用gcc。

编辑 1:

如果我改变这个循环

for(int k=0;k

进入

for(int k=0;k

那么有时候线程 1 连续 10 次 CPU,线程 2 连续 5 次 CPU,线程 3 连续 5 次 CPU,主线程连续 2 次,线程 4 连续 7 次 CPU。看起来不同的线程在随机时间被抢占。

这些随机数次连续 CPU 分配给不同线程的任何线索。??

【问题讨论】:

    标签: c++ linux multithreading pthreads posix


    【解决方案1】:

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

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

    承认你的电脑可以用ns做100条指令 承认 make 1 print 相当于使用 25 个指令 承认每个线程都有1ns可以工作

    现在您必须了解计算机中的所有程序都在消耗 100 条可用指令

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

    你明白了吗?

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      相关资源
      最近更新 更多