刚开始的代码是这样的:
#include
#include
#include
#include
void* thread(void *arg) {
char ch = *(char *)arg;
while(1) {
printf("%c",ch);
fflush(stdout);
//sleep(1);
}
}
int main(int argc, char *argv[]) {
pthread_t t1, t2;
char ch1 = 'A', ch2 = 'B';
pthread_create(&t1, NULL, thread, (void*)&ch1);
pthread_create(&t2, NULL, thread, (void*)&ch2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
此时输出A 和B都是随机的,我现在想要只输出A而不输出B,也就是需要改变线程的优先级。
下面的代码设置两个线程的优先级为100 和 200,按道理来说应该只会输出优先级高的线程,结果却和前面一样,两个都会输出。
#include
#include
#include
#include
void* thread(void *arg) {
char ch = *(char *)arg;
while(1) {
printf("%c",ch);
fflush(stdout);
//sleep(1);
}
}
int main(int argc, char *argv[]) {
pthread_t t1, t2;
pthread_attr_t attr;
struct sched_param sch;
char ch1 = 'A', ch2 = 'B';
pthread_attr_init(&attr);
pthread_attr_getschedparam(&attr, &sch);
sch.sched_priority = 100;
pthread_attr_setschedparam(&attr, &sch);
pthread_create(&t1, &attr, thread, (void*)&ch1);
sch.sched_priority = 200;
pthread_attr_setschedparam(&attr, &sch);
pthread_create(&t2, &attr, thread, (void*)&ch2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
上网查发现是linux调度策略的问题,linux有多种调度策略,在某些调度策略下线程优先级高只是代表它有更大的几率获得CPU资源,并不是说优先级高的就一定比优先级低的先获得CPU,网上搜到的调度策略如下:
1.SCHED_OTHER 分时调度策略
2.SCHED_FIFO 实时调度策略,先到先服务。一旦占用cpu则一直运行。一直运行直到有更高优先级任务到达或自己放弃
3.SCHED_RR实 时调度策略,时间片轮转。当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平
由上面可知要实现我的需求应该设置调度策略为 SCHED_FIFO,可是怎么设置呢?继续百度,发现用户空间程序可以使用sched_setscheduler()
来设定用户进程的调度策略。
通过man手册查看函数的用法。发现这是设置进程的,而不是线程。
pthread_attr_setschedpolicy
是设置线程调度策略的函数,使用了这个函数之后发现还是不行,再问,发现需要先设置线程的调度属性,因为默认情况下线程的调度属性是继承的,此时设置是无效的,我们必须先通过pthread_attr_setinheritsched
设置PTHREAD_EXPLICIT_SCHED(默认是PTHREAD_INHERIT_SCHED)后pthread_attr_setschedpolicy设置调度策略才是有效的。
可问题是即使我按照如上操作进行,最后的结果也不是我想要的,最后在网上一篇博客的帮助下才解决,
(3条消息) 【Linux】实时线程的优先级设置、调度和抢占_gpeng832的博客-CSDN博客
原来是要显式的指定每个线程要绑定在哪个CPU上,最终代码如下:
需要注意的点有:
#define _GNU_SOURCE
#include
#include
#include
#include
#include
int attach_cpu(int cpu_index);
void* thread(void *arg);
static int get_thread_policy(pthread_attr_t *attr);
int main(int argc, char *argv[]) {
pthread_t t1, t2;
char ch1 = 'A', ch2 = 'B';
pthread_attr_t attr1, attr2;
pthread_attr_init(&attr1);
pthread_attr_init(&attr2);
struct sched_param sch1, sch2;
sch1.sched_priority = 8;
sch2.sched_priority = 10;
pthread_attr_setinheritsched(&attr1, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setinheritsched(&attr2, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setschedpolicy(&attr1, SCHED_FIFO);
pthread_attr_setschedpolicy(&attr2, SCHED_FIFO);
pthread_attr_setschedparam(&attr1, &sch1);
pthread_attr_setschedparam(&attr2, &sch2);
pthread_create(&t1, &attr1, thread, (void*)&ch1);
pthread_create(&t2, &attr2, thread, (void*)&ch2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
void* thread(void *arg) {
attach_cpu(0);
char ch = *(char *)arg;
while(1) {
printf("%c",ch);
fflush(stdout);
//sleep(1);
}
}
// 获取调度策略的函数
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;
}
attach_cpu函数中用到了许多没见过的函数。
sysconf(_SC_NPROCESSORS_CONF)是获取可用的CPU核数。
为了跨平台的需要,我们需要同时考虑在不同平台下获取机器处理器核数的方法。在这里我们考虑Linux与Windows两个平台,不同的平台有不同的方法来获取处理器核数。
在Windows平台下,我们可以使用GetSystemInfo( )这个函数来获取当前系统的一些软硬件信息。其中有一项即是当前机器中处理器的核数。通过如下语句即可获得所要的信息:
SYSTEM_INFO info;
GetSystemInfo(&info);
return info.dwNumberOfProcessors;而在Linux平台下,我们可以使用sysconf( )或者get_nprocs( )来获取处理器核数。下面分别介绍:
sysconf( )有unistd.h提供,要使用该函数需要#include,其参数可以是_SC_NPROCESSORS_CONF,也可以是_SC_NPROCESSORS_ONLN。sysconf(_SC_NPROCESSORS_CONF)返回系统可以使用的核数,但是其值会包括系统中禁用的核的数目,因此该值并不代表当前系统中可用的核数。而sysconf(_SC_NPROCESSORS_ONLN)的返回值真正的代表了系统当前可用的核数。 GNU C库提供了另外一种获取机器可用核数的方法。函数int
get_nprocs_conf (void),int get_nprocs (void)在 sys/sysinfo.h中定义,这两个函数可用获取机器的核数。其中get_nprocs_conf (void)的返回值与sysconf(_SC_NPROCESSORS_CONF)类似,并不真正表名当前可用核数;而get_nprocs
(void)的返回值与sysconf(_SC_NPROCESSORS_ONLN)类似,真正的反映了当前可用核数。
cpu_set_t mask; 创建一个CPU集合
CPU_ZERO(&mask);将该集合清零
CPU_SET(cpu_index, &mask); 添加第cpu_index个内核到maskCPU集合中
pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask)这个函数可能是设置第一个参数中的线程只使用CPU集合mask中的CPU,第二个参数是CPU集合中CPU的个数。