简体   繁体   English

Pthread优先级和调度

[英]Pthread Priority and Scheduling

I am trying to use Pthreads to set priorities and scheduling policies. 我正在尝试使用Pthreads设置优先级和调度策略。

I modified a simple socket (downloadable online), with a server and several clients. 我修改了一个带有服务器和几个客户端的简单套接字(可在线下载)。 These clients are simply sending a string to the server. 这些客户端只是向服务器发送一个字符串。

The server is creating a new thread for each client connecting and is setting a higher priority to every new connection, which means the last client connected is the one with the highest priority. 服务器正在为每个连接的客户端创建一个新线程,并为每个新连接设置更高的优先级,这意味着最后连接的客户端是优先级最高的客户端。 The result I am expecting is that the thread with highest priority is the one printing out until that client is connected, while the others should wait. 我期望的结果是,具有最高优先级的线程是一直打印到该客户端连接的线程,而其他线程应该等待。

However, this is not the result I am getting. 但是,这不是我得到的结果。 The threads are all executed anyway, even the ones with lower priorities. 无论如何,所有线程都会执行,即使优先级较低的线程也是如此。 I even tried several configurations, for instance using pthread_join, but in this case the scheduler will wait until that thread has finished its execution, which is wrong if another thread with higher priority is called (in my example another client connecting), since it should release the CPU to this newly created thread. 我什至尝试了几种配置,例如使用pthread_join,但是在这种情况下,调度程序将等到该线程完成执行,如果调用了另一个优先级更高的线程(在我的示例中为另一个客户端连接),这是错误的,因为它应该将CPU释放到此新创建的线程。

Here is the code: 这是代码:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <pthread.h>
#include <sched.h>
#include <sys/time.h>

#define PORTNUMBER 8888

int prioInit = 30; //global variable to initialize priority

struct serverParm 
{
       int connectionDesc;
};

//function used to increase priority to new threads
void addPrio(int *prio)
{
  *prio = *prio + 10;
}

void *serverThread(void *parmPtr) 
{
  #define PARMPTR ((struct serverParm *) parmPtr)
  int recievedMsgLen;
  char messageBuf[1025];

  struct sched_param Priority_Param; //struct to set priority
  int policy=SCHED_FIFO; //kind of policy desired, either SCHED_FIFO or SCHED_RR, otherwise Linux uses SCHED_OTHER

  // Server thread code to deal with message processing
  printf("DEBUG: connection made, connectionDesc=%d\n",
        PARMPTR->connectionDesc);

  pthread_t self_id= pthread_self(); // I ask for the tid..
  Priority_Param.sched_priority = prioInit; //.. set the priority (the higher the sooner it is executed, min at 1, max at 99)..
  addPrio(&prioInit); //..increase the base priority..
  if(pthread_setschedparam(self_id, policy, &Priority_Param) != 0) //.. and set the scheduling options.
  {
    printf("Error Set Sched\n");
    perror("");
    exit(1);
  }

  if (PARMPTR->connectionDesc < 0) 
  {
    printf("Accept failed\n");
    exit(1);   
  }

  // Receive messages from sender
  while ((recievedMsgLen=
        read(PARMPTR->connectionDesc,messageBuf,sizeof(messageBuf)-1)) > 0) 
  {
    recievedMsgLen[messageBuf] = '\0';
    printf("Message: %s\n",messageBuf);
  }
  close(PARMPTR->connectionDesc);  // Avoid descriptor leaks 
  free(PARMPTR);                   // And memory leaks                        
}

int main () 
{
  int listenDesc;
  struct sockaddr_in myAddr;
  struct serverParm *parmPtr;
  int connectionDesc;
  pthread_t threadID;

  // Create socket from which to read 
  if ((listenDesc = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
  {
    perror("open error on socket");
    exit(1);
  }

  // Create "name" of socket
  myAddr.sin_family = AF_INET;
  myAddr.sin_addr.s_addr = INADDR_ANY;
  myAddr.sin_port = htons(PORTNUMBER);

  if (bind(listenDesc, (struct sockaddr *) &myAddr, sizeof(myAddr)) < 0) 
  {
    perror("bind error");
    exit(1);
  }

  // Start accepting connections
  listen(listenDesc,5);

  while (1)
  {
    // Wait for a client connection
    connectionDesc = accept(listenDesc, NULL, NULL);

    // Create a thread to actually handle this client
    parmPtr = (struct serverParm *)malloc(sizeof(struct serverParm));
    parmPtr->connectionDesc = connectionDesc;
    if (pthread_create(&threadID, NULL, serverThread, (void *)parmPtr) 
          != 0) 
    {
      perror("Thread create error");
      close(connectionDesc);
      close(listenDesc);
      exit(1);
    }

    printf("Parent ready for another connection\n");
  }

}

I am compiling using -pthread option and running as root, so that the policy and priority is set and changed. 我正在使用-pthread选项进行编译并以root身份运行,因此可以设置和更改策略和优先级。 I am for sure missing something here, but I am also wondering if it is possible to really use and change the scheduling options, in order to have a behavior similar to the real-time one. 我肯定在这里遗漏了一些东西,但是我也想知道是否有可能真正使用和更改计划选项,以使行为类似于实时选项。

Scheduler policy and priority is used to determine which thread will run when a choice must be made between two or more runnable threads . 调度程序策略和优先级用于确定必须在两个或多个可运行线程之间进行选择时将运行哪个线程

If your high priority thread blocks in read() , then it is not eligible to run, and a lower priority thread that is runnable will get a chance to run instead. 如果您的高优先级线程在read()阻塞,则它不符合运行的条件,而可运行的低优先级线程将有机会运行。 What the priority means is that even all of the available CPU cores are running lower priority threads at the moment when data arrives from the network for the higher priority thread, a lower priority thread will be immediately pre-empted so that the higher priority thread can run. 优先级意味着在数据从网络到达高优先级线程的那一刻,即使所有可用的CPU内核都在运行低优先级线程,低优先级线程将立即被抢占,以便高优先级线程可以跑。

If you want to see the effect of priority, have a lower-priority thread do lots of work so that it is almost always using the CPU: your higher-priority thread should still respond immediately to network input. 如果要查看优先级的影响,请让低优先级的线程进行大量工作,以便几乎总是使用CPU:较高优先级的线程仍应立即响应网络输入。

(But if you do this, either use a non-realtime priority level for the lower-priority threads, or make sure you have a shell open that is running at an elevated realtime priority, so that the lower-priority thread doesn't block your shell from running when you need it). (但是,如果这样做,请为低优先级线程使用非实时优先级级别,或者确保您以较高的实时优先级运行的外壳打开,以使低优先级线程不会阻塞您的shell在需要时无法运行)。

Side note: your addPrio() function is racy - it should lock a mutex around the changes to *prio . 旁注:您的addPrio()函数非常实用-它应将互斥锁锁定对*prio addPrio()的更改。

Regarding your ultimate goal of evaluating Linux's real behaviour in comparison to one with the premp-rt patch, the answer is not difficult. 关于与带premp-rt补丁的Linux相比,评估Linux真实行为的最终目的,答案并不难。

Of course it behaves similarly, it's just that the latencies are higher are wildly variable, but still bounded. 当然,它的行为类似,只是时延较高,可以随意变化,但仍然有限。

You can write real time software for stock Linux that will work perfectly satisfactorily, provided that your real time response requirements aren't that challenging. 您可以编写适用于现有Linux的实时软件,只要您对实时响应的要求没有那么大的挑战,它将可以完美地令人满意地工作。 If those requirements are to respond within a few milliseconds then you are going to need the premp-rt patches. 如果这些要求要在几毫秒内响应,那么您将需要premp-rt补丁。 If your requirements are tighter even than that then you'd need a different OS (VxWorks, etc). 如果您的要求比这更严格,那么您将需要其他操作系统(VxWorks等)。

There's some really good advise here and especially here . 这里尤其是这里有一些非常好的建议。 Linux preempt-rt and real time is not perfect, especially on Intel hardware, but if your requirements aren't that tight then you can do very well. Linux preempt-rt和实时性不是完美的,尤其是在Intel硬件上,但是如果您的要求不是那么严格,那么您可以做得很好。

I can highly recommend downloading and applying preempt-rt yourself. 我强烈建议您自己下载并应用preempt-rt。 That way you can compile FTRACE into your kernel and then you can play with kernelshark . 这样,您可以将FTRACE编译到内核中,然后可以使用kernelshark You can put FTRACE Into a stock kernel too. 您也可以将FTRACE放入股票内核。 Kernelshark is extremely useful when developing multi threaded applications, especially when you turn on task plots . Kernelshark在开发多线程应用程序时特别有用,尤其是在打开任务图时

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM