看了一些关于Linux多线程编程的书籍和网络资料,发现关于对实时线程调度和抢占的主题的代码和文章比较少(也可能是我还没找到)。而对于一些系统,例如机器人控制系统,对于任务的实时性要求是比较高的,所以需要了解一下实时线程的编程方法。
Linux虽然是一个非实时操作系统,但是其线程也有实时和分时之分,具体的调度策略可以分为3种:
实时线程:SCHED_FIFO(先来先服务策略调度);
实时线程:SCHED_RR(时间片轮转);
普通线程:Linux中称为SCHED_MORMAL;POSIX称为SCHED_OTHER,是一种分时调度策略。
我们创建线程的时候可以指定调度策略,默认的调度策略为SCHED_OTHER。
下边给出一个Linux实时线程抢占的编程示例,我认为尤其需要注意的两点是:
(1)必须在sudo模式下运行程序;
(2)需要将实时线程绑定到同一个CPU核上;
#include
#include
#include
#include
#include
#define __USE_GNU
long long a = 0;
long long b = 0;
// 获取调度策略的函数
static int get_thread_policy(pthread_attr_t *attr)
{
int policy;
int rs = pthread_attr_getschedpolicy(attr, &policy);
// assert(rs == 0);
switch (policy)
{
case SCHED_FIFO:
printf("policy= SCHED_FIFO\n");
break;
case SCHED_RR:
printf("policy= SCHED_RR");
break;
case SCHED_OTHER:
printf("policy=SCHED_OTHER\n");
break;
default:
printf("policy=UNKNOWN\n");
break;
}
return policy;
}
// 将线程绑定到某个cpu核上
int attach_cpu(int cpu_index)
{
int cpu_num = sysconf(_SC_NPROCESSORS_CONF);
if (cpu_index < 0 || cpu_index >= cpu_num)
{
printf("cpu index ERROR!\n");
return -1;
}
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(cpu_index, &mask);
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)
{
printf("set affinity np ERROR!\n");
return -1;
}
return 0;
}
// 线程函数1
void *thread1(void *param)
{
attach_cpu(0);
long long i;
for (i = 0; i < 10000000000; i++)
{
a++;
}
}
// 线程函数2
void *thread2(void *param)
{
attach_cpu(0);
long long i;
for (i = 0; i < 10000000000; i++)
{
b++;
}
}
int main()
{
pthread_t t1;
pthread_t t2;
pthread_attr_t attr1;
pthread_attr_t attr2;
struct sched_param param1;
struct sched_param param2;
//1、初始化
pthread_attr_init(&attr1);
pthread_attr_init(&attr2);
//2、自己决定调度策略
pthread_attr_setinheritsched(&attr1, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setinheritsched(&attr2, PTHREAD_EXPLICIT_SCHED);
//3、设置调度策略
pthread_attr_setschedpolicy(&attr1, SCHED_FIFO);
pthread_attr_setschedpolicy(&attr2, SCHED_FIFO);
// 获取调度策略
get_thread_policy(&attr1);
get_thread_policy(&attr2);
//4、设置优先级
param1.sched_priority = 10;// 线程1设置优先级为10
param2.sched_priority = 12;// 线程2设置优先级为12
pthread_attr_setschedparam(&attr1, ¶m1);
pthread_attr_setschedparam(&attr2, ¶m2);
//5、创建线程
pthread_create(&t1, &attr1, thread1, NULL);
sleep(1);
pthread_create(&t2, &attr2, thread2, NULL);
while (1)
{
printf("a=%lld, b=%lld\n", a, b);
sleep(1);
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
这里线程2的优先级设置为12,大于线程1的优先级11,所以线程2一旦就绪,就会抢占CPU资源,进入运行态,而线程1进入就绪态。如下所示,线程函数1中的a累加到366407710后就不再累加,被线程函数2中的b累加抢占,持续运行下去。
[linux-xx@xxx]$ sudo ./test
policy= SCHED_FIFO
policy= SCHED_FIFO
a=366407710, b=0
a=366407710, b=360397117
a=366407710, b=720418977
a=366407710, b=1080623671
a=366407710, b=1443246909
a=366407710, b=1802815022
a=366407710, b=2165877123
^C