内核模块代码:
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
static struct workqueue_struct *queue;
static void work_func(struct work_struct *work)
{
int i = 0;
while (i < 5) {
printk(KERN_INFO "%d\n", i);
usleep_range(1000000, 1000001);
i++;
}
}
DECLARE_WORK(work, work_func);
int init_module(void)
{
queue = create_workqueue("myworkqueue");
queue_work(queue, &work);
return 0;
}
void cleanup_module(void)
{
cancel_work_sync(&work);
destroy_workqueue(queue);
}如果我这样做了:
insmod mymod.ko
rmmod mymodrmmod挂在cancel_work_sync上,它首先等待工作完成,直到计数结束。
是否可以立即取消该工作项?
最小可运行示例这里。
在Linux内核4.9中进行了测试。
发布于 2020-11-30 09:24:51
还有一种方法可以用信号来阻止线程。这种方法比您的更好,因为它不需要线程定期醒来并使用kthread_should_stop()轮询停止变量。没有浪费CPU时间,它允许您的线程睡觉,只要它需要。
static int kthread_handle(void *param)
{
allow_signal(SIGINT);
allow_signal(SIGKILL);
for (;;)
{
// ...
// Some blocking functions such as kernel_read()/kernel_write()
// ...
if (signal_pending(current))
{
goto end;
}
// ...
// Some interruptible functions
// ...
if (mutex_lock_interruptible(...) == -EINTR)
{
goto end;
}
}
end:
while (!kthread_should_stop())
{
schedule();
}
return 0;
}
static int __init drv_init(void)
{
// Create and start kernel thread
kthread = kthread_run(kthread_handle, NULL, "kthread");
return 0;
}
static void __exit drv_exit(void)
{
send_sig(SIGKILL, kthread, 1);
kthread_stop(kthread);
}
module_init(drv_init);
module_exit(drv_exit);我不知道如何向工作队列发送信号,所以到目前为止,解决方案只适用于k线程。
发布于 2017-05-16 08:28:09
原子控制变量
我无法找到在工作队列中停止工作的方法,但是使用简单的控制变量是一种可能的解决方案。
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h> /* atomic_t */
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
static struct workqueue_struct *queue;
static atomic_t run = ATOMIC_INIT(1);
static void work_func(struct work_struct *work)
{
int i = 0;
while (atomic_read(&run)) {
printk(KERN_INFO "%d\n", i);
usleep_range(1000000, 1000001);
i++;
if (i == 10)
i = 0;
}
}
DECLARE_WORK(work, work_func);
int init_module(void)
{
queue = create_workqueue("myworkqueue");
queue_work(queue, &work);
return 0;
}
void cleanup_module(void)
{
atomic_set(&run, 0);
destroy_workqueue(queue);
}kthread_stop
工作队列是基于k线程的,在该示例中,工作队列基本上是无用的,因此我们可以直接使用k线程。
kthread_stop等待线程返回。
另请参阅:
线程中的信号处理似乎是一个有争议的主题,现在不可能了:https://unix.stackexchange.com/questions/355280/how-signals-are-handled-in-kernel
#include <linux/delay.h> /* usleep_range */
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
static struct task_struct *kthread;
static int work_func(void *data)
{
int i = 0;
while (!kthread_should_stop()) {
printk(KERN_INFO "%d\n", i);
usleep_range(1000000, 1000001);
i++;
if (i == 10)
i = 0;
}
return 0;
}
int init_module(void)
{
kthread = kthread_create(work_func, NULL, "mykthread");
wake_up_process(kthread);
return 0;
}
void cleanup_module(void)
{
kthread_stop(kthread);
}定时器
直接在中断上下文中运行,这样更准确,但更受限制。
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
static void callback(unsigned long data);
static unsigned long onesec;
DEFINE_TIMER(mytimer, callback, 0, 0);
static void callback(unsigned long data)
{
pr_info("%u\n", (unsigned)jiffies);
mod_timer(&mytimer, jiffies + onesec);
}
int init_module(void)
{
onesec = msecs_to_jiffies(1000);
mod_timer(&mytimer, jiffies + onesec);
return 0;
}
void cleanup_module(void)
{
del_timer(&mytimer);
}https://stackoverflow.com/questions/43973583
复制相似问题