zoukankan      html  css  js  c++  java
  • Linux内核多线程(二)

    内核多线程是在项目中使用到,自己也不熟悉,遇到一个很囧的问题,导致cpu运行100%。

    这是写的第一个内核线程程序,通过全局变量来实现两个内核线程之间的通信。但是这里遇到致命错误,就是:每当 wait_event_interruptible()被wake_up_interruptible 唤醒之后线程就进入死循环。后面发现是线程不会主动的自己调度,需要显式的通过schedule 或者 schedule_timeout()来调度。如果不加tc = 0 这一行,wait_event_intrruptible()就一直不会睡眠(参见前面的文章“等待队列”),不会被调度放弃CPU,因此进入死循环。这个过程可以通过分析wait_event_intrruptible()的源代码来看出。

    #include <linux/init.h>   
    
    #include <linux/module.h>   
    
    #include <linux/kthread.h>   
    
    #include <linux/wait.h>
    
      
    MODULE_LICENSE("Dual BSD/GPL");  
    
      
    static struct task_struct * _tsk;  
    
    static struct task_struct * _tsk1;
    
    static int tc = 0;
    
    static wait_queue_head_t log_wait_queue;
    
      
    
    static int thread_function(void *data)  
    {  
    
        do {  
    
                    printk(KERN_INFO "IN thread_function thread_function: %d times \n", tc);    
    
            
                       wait_event_interruptible(log_wait_queue,tc == 10);
    
                       tc = 0;  ///必须加这一行,内核才会进行调度。内核线程不像应用程序会主动调度,我们需要显式的使用调度函数,想要在thread_function_1中去重置tc的值是不可能的,因为线程不会被调度,该线程会一直占用CPU
    
                               
                       printk(KERN_INFO "has been woke up !\n");
    
        }while(!kthread_should_stop());  
    
        return tc;  
    }  
    
    
    static int thread_function_1(void *data)  
    {  
    
        do {  
    
                  printk(KERN_INFO "IN thread_function_1 thread_function: %d times\n", ++tc);  
    
           
    
                       if(tc == 10 && waitqueue_active(&log_wait_queue))
    
                       {
    
                                wake_up_interruptible(&log_wait_queue);
    
                       }
    
                       msleep_interruptible(1000);
    
                      
        }while(!kthread_should_stop());  
    
        return tc;  
    
    }  
    
      
    static int hello_init(void)  
    
    {  
    
        printk(KERN_INFO "Hello, world!\n");  
    
        init_waitqueue_head(&log_wait_queue);
    
        _tsk = kthread_run(thread_function, NULL, "mythread"); 
    
        if (IS_ERR(_tsk)) {  //需要使用IS_ERR()来判断线程是否有效,后面会有文章介绍IS_ERR()
    
            printk(KERN_INFO "first create kthread failed!\n");  
    
        }  
    
        else {  
    
            printk(KERN_INFO "first create ktrhead ok!\n");  
    
        }  
    
              _tsk1 = kthread_run(thread_function_1,NULL, "mythread2");
    
        if (IS_ERR(_tsk1)) {  
    
            printk(KERN_INFO "second create kthread failed!\n");  
    
        }  
    
        else {  
    
            printk(KERN_INFO "second create ktrhead ok!\n");  
    
        }  
    
        return 0;  
    
    }  
    
      
    static void hello_exit(void)  
    {  
    
        printk(KERN_INFO "Hello, exit!\n");  
    
        if (!IS_ERR(_tsk)){  
    
            int ret = kthread_stop(_tsk);  
    
            printk(KERN_INFO "First thread function has stopped ,return %d\n", ret);  
    
        }  
    
        if(!IS_ERR(_tsk1))
    
             {
    
                       int ret = kthread_stop(_tsk1);
    
                       printk(KERN_INFO "Second thread function_1 has stopped ,return %d\n",ret);
    
             }
    
    }  
    
      
    module_init(hello_init);  
    
    module_exit(hello_exit);  

    说明:这个程序的目的就是,使用一个线程(thread_function_1)通知另外一个线程(thread_function)某个条件(tc == 10)满足(比如接收线程收到10帧然后通知处理线程处理接收到的数据)

    运行结果:

    程序加载并运行(tc 的值等于10 之后 就会唤醒另外一个线程,之后tc又从10开始计数):

    程序卸载(程序卸载其实还是要很注意的,很多程序在卸载的时候回出现各种问题后面文章会提到):

  • 相关阅读:
    《剑指Offer》二维数组中的查找
    白话计算机入门书籍--《穿越计算机的迷雾》有感
    Mysql Cluster7.5.6在 windows10 部署安装
    Mysql Cluster7.5.6 windows10 部署安装
    lll
    线程控制
    动态链接库相关知识
    二分查找及其变种简单易懂的模版
    白话 STL next_permutation 原理
    Maven本地上有包还去网上找包
  • 原文地址:https://www.cnblogs.com/zhuyp1015/p/2545702.html
Copyright © 2011-2022 走看看