【发布时间】:2021-02-25 03:02:53
【问题描述】:
前言:
我有两个线程一个内核线程和一个用户空间pthread。我假设pthread 设置为SCHED_RR 具有更高的rt 优先级应该抢占kthread 和SCHED_RR 和更低的优先级。
我假设在 SCHED_RR 中具有足够高的优先级,pthread 可以抢占任何具有较低优先级的线程。但是我的测试失败了。 kthread 一直在运行,pthread 没有进展。
注意:我为这篇文章添加了 C 和 C++ 标签,因为我的示例是一个带有 C++ 和一个带有 C。如果任何标签适合这篇文章,请编辑它并删除 C 和 C++ 标签。
实验准备:
-
Ubuntu 18.04。 (我认为无论在普通 linux 还是 RT linux 上都是可行的)
-
kthread 是使用
SCHED_RR和 rt 优先级 50 创建的。- kthread 只是一个带有
udelay()的无限循环,它不应禁用抢占。 - kthread 在调用
udelay之前会检查kthread_should_stop()
- kthread 只是一个带有
-
pthread 是使用
SCHED_RR和 rt 优先级 70 创建的。- pthread 是一个繁忙的无限循环
- 创建的用户程序
pthread将调用pthread_join等到pthread按ctrl+c 结束
while( true ){
sleep( 1 );
std:: cout << "wake\n";
}
结果
如果kthread 先运行,用户程序会在pthread_join 调用后卡住。 pthread 的输出字符串在内核模块被移除之前无法接收(调用 kthread 停止)。
我的假设是 pthread 永远不会启动,因为控制台上没有打印输出。但我不确定这个假设是否正确。
参考
-
pthread 抢占 kthread 失败
- 收到this post 说明需要 RT linux。
-
How “real-time” are the FIFO/RR schedulers on non-RT Linux kernel?
- 帖子中的评论即使 CONFIG_PREEMPT 被禁用,它也应该可以工作。
重现实验的代码
==== 这是带有测试代码的文字墙 ====
kthread.c - 内核模块
#include <uapi/linux/sched/types.h> // For sched_param
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kthread.h> // kthread_create(), kthread_should_stop(), kthread_stop()
#include <linux/delay.h> // msleep()
#include <linux/sched.h> // For struct sched_param, sched_setcheduler()
#define MY_THREADNAME "kthread example"
#define MY_MODULENAME "kthread occupy cpu1 module"
#pragma GCC diagnostic ignored "-Wdeclaration-after-statement" // Ignore C90 declaration convention since gcc has extension for it.
MODULE_LICENSE( "GPL v2" );
MODULE_AUTHOR( "TEST" );
MODULE_DESCRIPTION( MY_MODULENAME );
struct task_struct *m_task1;
static int m_t1id = 1;
int thread_fn(void *data)
{
int id = *((int*)data);
int ret = 0;
int cpu = -1;
cpu = get_cpu();
put_cpu();
pr_info( "IN THREAD FUNCTION %d, CPU is %d \n", id, cpu);
while(!kthread_should_stop()){
// try to busy blocking cpu, but udelay doesn't disable preemption.
udelay(1000);
}
pr_info( "EXIT from thread function 1\n");
return 0;
}
static int __init init_my_module(void) {
pr_info( "Hello, %s!\n", MY_MODULENAME );
// Get cpu will disable preemption, so must put_cpu to enable preemption
int cpu = get_cpu();
put_cpu();
pr_info( "Current cpu for initializing is %d\n", cpu );
pr_info( "Current pid is %d\n", current->pid );
// threadfn, data, and printf-style name. Created thread would be suspended, need to wake up.
m_task1 = kthread_create(&thread_fn,(void *)&m_t1id,"testing kt%d",m_t1id);
pr_info( "T1 pid is %d", m_task1->pid );
kthread_bind(m_task1,1 );
// Set Realtime priority
struct sched_param param = {50};
sched_setscheduler( m_task1, SCHED_RR, ¶m );
pr_info( "T1 effective prio AFTER set policy= %d", m_task1->prio );
wake_up_process(m_task1);
return 0;
}
static void __exit exit_my_module(void) {
kthread_stop( m_task1 );
pr_info( "Bye, %s!\n", MY_MODULENAME );
}
module_init( init_my_module);
module_exit( exit_my_module);
kthread.c 的 Makefile
#Test on local ubuntu
KVERSION := $(shell uname -r)
KERNEL_DIR = /lib/modules/$(KVERSION)/build
PWD := $(shell pwd)
MODULE_NAME = kthread
obj-m = $(MODULE_NAME).o
all:
make -C $(KERNEL_DIR) M=$(PWD) modules
clean:
make -C $(KERNEL_DIR) M=$(PWD) clean
pthread.cpp
pthread.cpp 的编译命令行是g++ pthread.cpp -pthread
#include <pthread.h>
#include <sched.h>
#include <iostream>
#include <sys/resource.h> // to use getrusage
#include <unistd.h>
void* helloworld ( void *arg ){
int cpuid = sched_getcpu();
int sum = 0;
std::cout<< "Hello pthread on cpu " << cpuid << std::endl;
pthread_t pself = pthread_self();
int policy = 0;
struct sched_param sparam;
pthread_getschedparam( pself, &policy, &sparam );
std::cout << "Current thread Policy: " << policy << " prio:" << sparam.sched_priority << "\n";
int err = pthread_setschedprio( pself, 99 );
std::cout<< "set prio ret:"<< err <<"\n";
// keep sleep to check process priority
while( true ){
sleep( 1 );
std:: cout << "wake\n";
}
return NULL;
}
int main(void){
std::cout<<" pthread create\n";
pthread_t handle;
pthread_attr_t attr;
cpu_set_t cpus;
struct sched_param sparam;
int error = 0;
// Setting SCHED_FIFO must run program in sudo
int policy = SCHED_RR;
CPU_ZERO( &cpus );
// Set bit cpu0 to enable in mask.
CPU_SET( 1, &cpus );
pthread_attr_init( &attr );
// Let pthread using specified attribute explicitly
error = pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
std::cout << "set inherit sched result: "<< error << "\n";
error = pthread_attr_setschedpolicy( &attr, policy );
std::cout << "set policy result: "<< error << "\n";
// _np means "non-portable"
pthread_attr_setaffinity_np( &attr,sizeof(cpu_set_t), &cpus );
// Set priority
int max = 70;//sched_get_priority_max(policy);
sparam.sched_priority = max;// ( 4* min + 6*max )/10;
std::cout << "Set priority: " << sparam.sched_priority << "\n";
error = pthread_attr_setschedparam(&attr ,&sparam);
std::cout << "setschedparam: " << error << std::endl;
// before create thread, raise main thread as higher priority
error = pthread_setschedparam(pthread_self(), policy, &sparam);
std::cout<< "main thread set prio " << error << std::endl;
error = pthread_create( &handle, &attr , &helloworld, NULL );
std::cout<< "pthread_create " << error << std::endl;
void* retvalue;
pthread_join( handle, &retvalue );
pthread_attr_destroy( &attr );
return 0;
}
【问题讨论】:
标签: c++ linux linux-kernel pthreads scheduling