c - Linux线程优先级

标签 c linux multithreading pthreads

我对 Linux pthread 同步和调度有疑问,如下面的代码

/*
 * multithread.c
 *
 * Demonstrate use of a multi threading and scheduling using pthreads
 *
 * compile with
 cc multithread.c -o multithread -lrt -lpthread
 *
 */

#include <pthread.h>    /* header file for pthreads */
#include <unistd.h>     /* header file for POSIX conformance */
#include <time.h>       /* header file for POSIX time management */
#include <sched.h>      /* header file for POSIX scheduling */
#include <stdio.h>      /* header file for standard input/outputlibrary */
#define _REENTRANT      /* macro to ensure system calls are reentrant */

void *threadA(void *);   /* predefine threadA routine */
void *threadB(void *);   /* predefine threadB routine */
void *threadC(void *);   /* predefine threadC routine */

pthread_t threadA_id,threadB_id,threadC_id,main_id; /* thread identifiers */
pthread_attr_t attrA,attrB,attrC;  /* thread attribute structures */
struct sched_param param;          /* scheduling structure for thread attributes */

int policy=SCHED_FIFO;
int priority_min,priority_max;     /* for range of priority levels */

/* main routine */
int main()
{
  struct timespec start;
  int status;                        /* check that system calls return ok */

  clock_gettime(CLOCK_REALTIME, &start);        /* get the time   */
  printf("Start time is: %d seconds %d nano_seconds\n",start.tv_sec,start.tv_nsec);

  /* Set processor affinity */ 
  unsigned long mask = 1; /* use only 1 CPU core */
  unsigned int len = sizeof(mask);
  status = sched_setaffinity(0, len, &mask);
  if (status < 0) perror("sched_setaffinity");
  status = sched_getaffinity(0, len, &mask);
  if (status < 0) perror("sched_getaffinity");

  /* Find priority limits */

  priority_max = sched_get_priority_max(policy);
  priority_min = sched_get_priority_min(policy);

  /* Set priority and policy of main thread */

  main_id = pthread_self();
  param.sched_priority=priority_max;
  status = pthread_setschedparam(main_id, policy, &param);
  if (status != 0) perror("pthread_setschedparam"); /* error check */

  /* Create threadA */

  param.sched_priority = priority_min+1;
  pthread_attr_init(&attrA);
  status = pthread_attr_setschedpolicy(&attrA,policy);
  if (status != 0) perror("pthread_attr_setschedpolicy"); /* error check */
  status = pthread_attr_setschedparam(&attrA,&param);
  if (status != 0) perror("pthread_attr_setschedparam"); /* error check */
  status = pthread_create(&threadA_id, &attrA, threadA, NULL);
  if (status != 0) perror("pthread_create"); /* error check */
  status = pthread_setschedparam(threadA_id,policy,&param);
  if (status != 0) perror("pthread_setschedparam");

  /* Create threadB */

  param.sched_priority = priority_min+1;
  pthread_attr_init(&attrB);
  status = pthread_attr_setschedpolicy(&attrB,policy);
  if (status != 0) perror("pthread_attr_setschedpolicy"); /* error check */
  status = pthread_attr_setschedparam(&attrB,&param);
  if (status != 0) perror("pthread_attr_setschedparam"); /* error check */
  status = pthread_create(&threadB_id, &attrB, threadB, NULL);
  if (status != 0) perror("pthread_create"); /* error check */
  status = pthread_setschedparam(threadB_id,policy,&param);
  if (status != 0) perror("pthread_setschedparam");

  /* Create threadC */

  param.sched_priority = priority_min+1;
  pthread_attr_init(&attrC);
  status = pthread_attr_setschedpolicy(&attrC,policy);
  if (status != 0) perror("pthread_attr_setschedpolicy"); /* error check */
  status = pthread_attr_setschedparam(&attrC,&param);
  if (status != 0) perror("pthread_attr_setschedparam"); /* error check */
  status = pthread_create(&threadC_id, &attrC, threadC, NULL);
  if (status != 0) perror("pthread_create"); /* error check */
  status = pthread_setschedparam(threadC_id,policy,&param);
  if (status != 0) perror("pthread_setschedparam");

  /* Join threads - force main to wait for the thread to terminate */  
  printf("main() waiting for threads\n");

  status = pthread_join(threadA_id, NULL);
  if (status != 0) perror("pthread_join(threadA_id, NULL)"); /* error check */
  status = pthread_join(threadB_id, NULL);
  if (status != 0) perror("pthread_join(threadB_id, NULL)"); /* error check */
  status = pthread_join(threadC_id, NULL);
  if (status != 0) perror("pthread_join(threadC_id, NULL)"); /* error check */

  printf("\nmain() reporting that all threads have terminated\n");
  return(0);

}  /* end of main */

void *threadA(void *arg)
{
  int j;

  for(j=1;j<=10;j++){
    printf("a");
  }
  return (NULL);
}

void *threadB(void *arg)
{
  int j;

  for(j=1;j<=10;j++){
    printf("b");
  }
  return (NULL);
}

void *threadC(void *arg)
{
  int j;

  for(j=1;j<=10;j++){
    printf("c");
  }
  return (NULL);
}

我的问题是为什么这个线程的输出结果是这样的

output

为什么程序不首先打印 aaaaa 而不是 bbbbb 和最后一个 ccccc ?尽管我将线程优先级设置为除主线程外具有相同的优先级,并且我为线程处理设置了 FIFO 模式策略。

有没有人对这种情况或 linux 线程同步和调度有经验?

最佳答案

这里问题的症结在于,当线程变为可运行 时应用 SCHED_FIFO 策略。从手册页:

2) When a blocked SCHED_FIFO thread becomes runnable, it will be
   inserted at the end of the list for its priority.

您的示例清楚地表明,pthread_create() 返回与实际可运行的新线程之间存在差异。主线程被设置为最大优先级并且本身也是 FIFO,它完全阻止新线程被添加到运行队列,直到主线程最终阻塞在某些东西上。在这一点上,新创建的线程最初都以未指定的顺序获得,SCHED_FIFO 策略随后应用。

为了证明 SCHED_FIFO 确实有效,请考虑这个修改,它为每个线程添加一个信号量,并在主线程中延迟以使所有内容可运行一次:

/*
 * multithread.c
 *
 * Demonstrate use of a multi threading and scheduling using pthreads
 *
 * compile with
 cc multithread.c -o multithread -lrt -lpthread
 *
 */
#define _GNU_SOURCE
#define _XOPEN_SOURCE   700
#define _REENTRANT      /* macro to ensure system calls are reentrant */

#include <pthread.h>    /* header file for pthreads */
#include <unistd.h>     /* header file for POSIX conformance */
#include <time.h>       /* header file for POSIX time management */
#include <sched.h>      /* header file for POSIX scheduling */
#include <stdio.h>      /* header file for standard input/outputlibrary */
#include <semaphore.h>

void *threadA(void *);   /* predefine threadA routine */
void *threadB(void *);   /* predefine threadB routine */
void *threadC(void *);   /* predefine threadC routine */

pthread_t threadA_id,threadB_id,threadC_id,main_id; /* thread identifiers */
pthread_attr_t attrA,attrB,attrC;  /* thread attribute structures */
struct sched_param param;          /* scheduling structure for thread attributes */

int policy=SCHED_FIFO;
int priority_min,priority_max;     /* for range of priority levels */

sem_t sem1;
sem_t sem2;
sem_t sem3;

/* main routine */
int main()
{
  struct timespec start;
  int status;                        /* check that system calls return ok */

  clock_gettime(CLOCK_REALTIME, &start);        /* get the time   */
  printf("Start time is: %d seconds %d nano_seconds\n",start.tv_sec,start.tv_nsec);

  sem_init(&sem1, 0, 0);
  sem_init(&sem2, 0, 0);
  sem_init(&sem3, 0, 0);

  /* Set processor affinity */ 
  cpu_set_t mask;
  CPU_SET(1, &mask);  /* use only 1 CPU core */
  unsigned int len = sizeof(mask);
  status = sched_setaffinity(0, len, &mask);
  if (status < 0) perror("sched_setaffinity");
  status = sched_getaffinity(0, len, &mask);
  if (status < 0) perror("sched_getaffinity");

  /* Find priority limits */

  priority_max = sched_get_priority_max(policy);
  priority_min = sched_get_priority_min(policy);

  /* Set priority and policy of main thread */

  main_id = pthread_self();
  param.sched_priority=priority_max;
  status = pthread_setschedparam(main_id, policy, &param);
  if (status != 0) perror("pthread_setschedparam"); /* error check */

  /* Create threadA */

  param.sched_priority = priority_min+1;
  pthread_attr_init(&attrA);
  status = pthread_attr_setschedpolicy(&attrA,policy);
  if (status != 0) perror("pthread_attr_setschedpolicy"); /* error check */
  status = pthread_attr_setschedparam(&attrA,&param);
  if (status != 0) perror("pthread_attr_setschedparam"); /* error check */
  status = pthread_create(&threadA_id, &attrA, threadA, NULL);
  if (status != 0) perror("pthread_create"); /* error check */
  status = pthread_setschedparam(threadA_id,policy,&param);
  if (status != 0) perror("pthread_setschedparam");

  /* Create threadB */

  param.sched_priority = priority_min+1;
  pthread_attr_init(&attrB);
  status = pthread_attr_setschedpolicy(&attrB,policy);
  if (status != 0) perror("pthread_attr_setschedpolicy"); /* error check */
  status = pthread_attr_setschedparam(&attrB,&param);
  if (status != 0) perror("pthread_attr_setschedparam"); /* error check */
  status = pthread_create(&threadB_id, &attrB, threadB, NULL);
  if (status != 0) perror("pthread_create"); /* error check */
  status = pthread_setschedparam(threadB_id,policy,&param);
  if (status != 0) perror("pthread_setschedparam");

  /* Create threadC */

  param.sched_priority = priority_min+1;
  pthread_attr_init(&attrC);
  status = pthread_attr_setschedpolicy(&attrC,policy);
  if (status != 0) perror("pthread_attr_setschedpolicy"); /* error check */
  status = pthread_attr_setschedparam(&attrC,&param);
  if (status != 0) perror("pthread_attr_setschedparam"); /* error check */
  status = pthread_create(&threadC_id, &attrC, threadC, NULL);
  if (status != 0) perror("pthread_create"); /* error check */
  status = pthread_setschedparam(threadC_id,policy,&param);
  if (status != 0) perror("pthread_setschedparam");

  /* Join threads - force main to wait for the thread to terminate */  
  printf("main() waiting for threads\n");

  /* delay so all threads become blocked on semaphore */
  {
    struct timespec ts;
    ts.tv_sec = 0;
    ts.tv_nsec = 25000000;
    clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
  }

  /* post sems so threads become runnable in desired order */
  sem_post(&sem1);
  sem_post(&sem2);
  sem_post(&sem3);

  status = pthread_join(threadA_id, NULL);
  if (status != 0) perror("pthread_join(threadA_id, NULL)"); /* error check */
  status = pthread_join(threadB_id, NULL);
  if (status != 0) perror("pthread_join(threadB_id, NULL)"); /* error check */
  status = pthread_join(threadC_id, NULL);
  if (status != 0) perror("pthread_join(threadC_id, NULL)"); /* error check */

  printf("\nmain() reporting that all threads have terminated\n");
  return(0);

}  /* end of main */

void *threadA(void *arg)
{
  int j;

  printf("x");

  sem_wait(&sem1);

  for(j=1;j<=10;j++){
    printf("a");
  }
  return (NULL);
}

void *threadB(void *arg)
{
  int j;

  printf("y");

  sem_wait(&sem2);

  for(j=1;j<=10;j++){
    printf("b");
  }
  return (NULL);
}

void *threadC(void *arg)
{
  int j;

  printf("z");

  sem_wait(&sem3);

  for(j=1;j<=10;j++){
    printf("c");
  }
  return (NULL);
}

这个延迟允许所有三个线程被初始调度一次,然后它们各自在各自的信号量上被阻塞。然后主任务(仍然是最高优先级)发布所有三个信号量,因此所有三个线程都变得可运行,但是我们已经控制了它们变得可运行的顺序。这个在我的机器上的输出显示:

Start time is: 1520004544 seconds 516899746 nano_seconds
main() waiting for threads
zyxaaaaaaaaaabbbbbbbbbbcccccccccc
main() reporting that all threads have terminated

关于c - Linux线程优先级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49051398/

相关文章:

c - 原子计数器,达到 0 时可以禁用

php - 打印由 C 程序回显的行并在 PHP 网络服务器上显示它们

linux - 如何禁用 GtkMenuItem?

ios - 使用信号量从 Parse 返回图像

android - 使用多个线程下载图像会导致 OutOfMemory 异常

C++动态链接库和void指针

c - 从 C 中的非常量指针参数中释放字符串

windows - 适用于 Windows、Linux、MacOS X 的跨平台脚​​本

linux - 使用 shell globbing 匹配所有嵌套目录下的所有文件

java - 观察者/可观察模式的链接