Linux内核中实现生产者与消费者(避免无效唤醒)

本文关注的重点是,避免内核线程的无效唤醒,并且主要是关注消费者线程的设计。

因此,为了省事,这里关与生产者,消费者本身的处理流程可能不够严密。

1. 生产者

一个内核线程,每生产一个商品后,就唤醒消费者,然后自己睡眠1秒钟。

2. 消费者

一个内核线程,每当被唤醒后,就消费商品,然后进入睡眠。

对于消费者线程的这种设计,有几个好处:响应快,平时不占任何cpu。

但这种设计有一点要注意,那就是要避免线程的无效唤醒。如何实现,看看消费者线程的代码就知道了。

/*

* kernel programming test code

*

* Copyright (C) 2014 Sun Mingbao <[email protected]>

* Dual licensed under the MIT and/or GPL licenses.

*

*/

#include <linux/init.h>

#include <linux/module.h>

#include <linux/types.h>

#include <linux/kernel.h>

#include <linux/kthread.h>

#include <linux/proc_fs.h>

#include <linux/string.h>

MODULE_AUTHOR("Sun Mingbao <[email protected]>");

MODULE_DESCRIPTION("kernel programming test code");

MODULE_VERSION("1.0");

MODULE_LICENSE("Dual MIT/GPL");

#define  MODULE_NAME    "test"

#define    WRITE_CONSOLE(fmt, args...) \

do \

{ \

printk(KERN_ALERT fmt,##args); \

} while (0)

#define    DBG_PRINT(fmt, args...) \

do \

{ \

WRITE_CONSOLE(MODULE_NAME"_DBG:%s(%d)-%s:\n"fmt"\n", __FILE__,__LINE__,__FUNCTION__,##args); \

} while (0)

static struct task_struct *consumer_thread;

static struct task_struct *producer_thread;

static u32 cnt_consumer, cnt_producer;

static int has_something_to_consume = 0;

static void consume()

{

has_something_to_consume = 0;

cnt_consumer++;

}

static void produce()

{

has_something_to_consume = 1;

cnt_producer++;

}

static int consumer_thread_func(void * data)

{

while (!kthread_should_stop())

{

if (has_something_to_consume)

{

consume();

}

set_current_state(TASK_INTERRUPTIBLE);

if (has_something_to_consume)

{

set_current_state(TASK_RUNNING);

continue;

}

schedule();

}

if (has_something_to_consume)

{

consume();

}

}

static int producer_thread_func(void * data)

{

while (!kthread_should_stop())

{

produce();

if (consumer_thread->state & TASK_INTERRUPTIBLE)

{

wake_up_process(consumer_thread);

}

set_current_state(TASK_INTERRUPTIBLE);

schedule_timeout(HZ);

}

}

static int __init create_threads(void)

{

consumer_thread=kthread_run(consumer_thread_func, NULL, "consumer_thread");

producer_thread=kthread_run(producer_thread_func, NULL, "producer_thread");

return 0;

}

static struct proc_dir_entry *my_proc_dir;

static int misc_info_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)

{

int ret;

static char proc_file_contents[128];

static int proc_file_len = 0;

if (0==offset || 0==proc_file_len)

{

proc_file_len=sprintf(proc_file_contents, "cnt_producer:%u\n""cnt_consumer:%u\n", cnt_producer, cnt_consumer);

}

ret=snprintf(buffer, length, "%s", proc_file_contents+offset);

if(ret+offset==proc_file_len)

*eof = 1;

return ret;

}

static int __init create_my_proc_entries(void)

{

my_proc_dir = proc_mkdir(MODULE_NAME, NULL);

create_proc_read_entry("misc_info"

,0

, my_proc_dir

, misc_info_read_proc

, NULL);

return 0;

}

static void __exit remove_my_proc_entries(void)

{

remove_proc_entry("misc_info", my_proc_dir);

remove_proc_entry(MODULE_NAME, NULL);

}

static int __init test_init(void)

{

int retval;

DBG_PRINT("start");

retval=create_threads();

if (retval < 0)

{

goto EXIT;

}

create_my_proc_entries();

DBG_PRINT("start succeed");

EXIT:

return retval;

}

static void __exit stop_threads(void)

{

kthread_stop(consumer_thread);

kthread_stop(producer_thread);

}

static void __exit test_exit(void)

{

DBG_PRINT("quit");

remove_my_proc_entries();

stop_threads();

}

module_init(test_init);

module_exit(test_exit);

时间: 2024-09-29 09:10:31

Linux内核中实现生产者与消费者(避免无效唤醒)的相关文章

java多线程中的生产者与消费者之等待唤醒机制@Version1.0

一.生产者消费者模式的学生类成员变量生产与消费demo,第一版1.等待唤醒:    Object类中提供了三个方法:    wait():等待    notify():唤醒单个线程    notifyAll():唤醒所有线程2.为什么这些方法不定义在Thread类中呢?  这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象.  所以,这些方法必须定义在Object类中.3.当我们在使用多线程的时候有的时候需要,一条线程产生一个数据,另一条线程接着消费一个数据,一边生产一边消费,

java多线程中的生产者与消费者之等待唤醒机制@Version2.0

二.生产者消费者模式的学生类成员变量生产与消费demo, @Version2.0 在学生类中添加同步方法:synchronized get()消费者,synchronized set()生产者 最终版的代码中: 把student的成员变量给私有化了, 把设置和获取的功能给封装成了功能,并加了同步, 设置或者获取的线程里面只需要调用方法即可. 1.等待唤醒:    Object类中提供了三个方法:    wait():等待    notify():唤醒单个线程    notifyAll():唤醒所

Linux内核中常用String库函数实现

//只列举了部分常用的strcpy,strcmp,strcat,strchr,strstr,strpbrk...  char *strcpy(char *dest, const char *src) { char *tmp = dest; while ((*dest++ = *src++) != '\0') /* nothing */; return tmp; } char *strncpy(char *dest, const char *src, size_t count) { char *t

Linux内核中的jiffies及其作用介绍及jiffies等相关函数详解

在LINUX的时钟中断中涉及至二个全局变量一个是xtime,它是timeval数据结构变量,另一个则是jiffies,首先看timeval结构struct timeval{time_t tv_sec; /***second***/susecond_t tv_usec;/***microsecond***/}到底microsecond是毫秒还是微秒?? 1秒=1000毫秒(3个零),1秒=1000 000微秒(6个零),1秒=1000 000 000纳秒(9个零),1秒=1000 000 000

Java中的生产者、消费者问题

Java中的生产者.消费者问题描述: 生产者-消费者(producer-consumer)问题, 也称作有界缓冲区(bounded-buffer)问题, 两个进程共享一个公共的固定大小的缓冲区(仓库). 其中一个是生产者, 用于将产品放入仓库: 另外一个是消费者, 用于从仓库中取出产品消费. 问题出现在当仓库已经满了, 而此时生产者还想向其中放入一个新的产品的情形, 其解决方法是让生产者此时进行等待, 等待消费者从仓库中取走了一个或者多个产品后再去唤醒它. 同样地, 当仓库已经空了, 而消费者还

route-显示并设置Linux内核中的网络路由表

route命令 网络配置 route命令用来显示并设置Linux内核中的网络路由表,route命令设置的路由主要是静态路由.要实现两个不同的子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现. 语法 route(选项)(参数) 选项 -A:设置地址类型: -C:打印将Linux核心的路由缓存: -v:详细信息模式: -n:不执行DNS反向查找,直接显示数字形式的IP地址: -e:netstat格式显示路由表: -net:到一个网络的路由表: -host:到一个主机的路

C语言在linux内核中do while(0)妙用之法

为什么说do while(0) 妙?因为它的确就是妙,而且在linux内核中实现是相当的妙,我们来看看内核中的相关代码: #define db_error(fmt, ...) do { fprintf(stderr, "(error): "); fprintf(stderr, fmt, ##__VA_ARGS__); } while (0) 这只是个普通的调试信息的输出,有人便会认为,你这不是多此一举吗?去掉do while(0)不一样也实现了吗?其实不然,我们看看例子就清楚了,尽管很

Linux内核中的中断栈与内核栈的补充说明【转】

转自:http://blog.chinaunix.net/uid-12461657-id-3487463.html 原文地址:Linux内核中的中断栈与内核栈的补充说明 作者:MagicBoy2010 中断栈与内核栈的话题更多地属于内核的范畴,所以在<深入Linux设备驱动程序内核机制>第5章“中断处理”当中,基本上没怎么涉及到上述内容,只是在5.4节有些许的文字讨论中断栈在中断嵌套情形下可能的溢出问题. 本贴在这个基础上对内核栈与中断栈的话题做些补充,讨论基于x86 32位系统,因为64位系

向linux内核中添加外部中断驱动模块

本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内核中添加外部中断驱动模块.7.完整驱动程序代码.linux的内核版本为linux2.6.32.2. 一.linux模块的框架以及混杂设备相关知识 1.内核模块的框架如下图所示,其中module_init()(图中有误,不是modules_init)只有在使用insmod命令手动加载模块时才会被调用,