Linux创建线程使用kernel_thread(),kthread_run()
#include <linux/kthread.h>
#include <linux/module.h>
#ifndef SLEEP_MILLI_SEC
#define SLEEP_MILLI_SEC(nMilliSec) \
do { \
long timeout = (nMilliSec) * HZ / 1000; \
while(timeout > 0) \
{ \
timeout = schedule_timeout(timeout); \
} \
}while(0);
#endif
static struct task_struct * MyThread = NULL;
static int MyPrintk(void *data)
{
char *mydata = kmalloc(strlen(data)+1,GFP_KERNEL);
memset(mydata,'\0',strlen(data)+1);
strncpy(mydata,data,strlen(data));
while(!kthread_should_stop())
{
SLEEP_MILLI_SEC(1000);
printk("%s\n",mydata);
}
kfree(mydata);
return 0;
}
static int __init init_kthread(void)
{
MyThread = kthread_run(MyPrintk,"hello world","mythread");
return 0;
}
static void __exit exit_kthread(void)
{
if(MyThread)
{
printk("stop MyThread\n");
kthread_stop(MyThread);
}
}
module_init(init_kthread);
module_exit(exit_kthread);
MODULE_AUTHOR("MallocFree");
sudo cat /proc/kmsg
Linux的同步
struct semaphore,struct mutex,completion(event),spinlock_t,rwlock_t,atomic variables
semaphore
void sema_init(struct semaphore *sem,int val);
DEFINE_SEMAPHORE(name)
void down(struct semaphore *sem);
down_interruptible()//可以唤醒
down_trylock()//不会睡眠
void up(struct semaphore *sem)
mutex
static DEFINE_MUTEX(mymutex);
mutex_lock(&mymutex);
g_i++;
mutex_unlock(&mymutex);
mutex_lock_interruptible()//可以唤醒
mutex_trylock()//不会睡眠
SPINLOCK
spinlock_t my_lock=SPIN_LOCK_UNLOCKED;
spin_init(&my_lock);
spin_lock(&my_lock);
g_i++;
spin_unlock(&my_lock);
rwlock
与SPINLOCK用法一样
rwlock_t my_lock=RW_LOCK_UNLOCKED;
rwlock_t my_lock;
spin_init(&my_lock);
read_lock(&my_lock);
g_i++;
read_unlock(&my_lock);
struct completion
类似windows的event
//定义和初始化
struct completion my_completion;
init_completion(&my_completion);
//1.wait
wait_for_completion(&my_completion);
//2.完成
complete(&my_completion);//唤醒一个
complete_all(&my_completion);
原子操作
atomic_t v;
void atomic_set(atomic_t ,int i);//v=i
atomic_t v=ATOMIC_INIT(0);//v=0
int x=atomic_read(v);
......
timer
timer_list s_timer;
init_timer(&s_timer);
内核中断上半部与下半部机制
为了最大程度避免中断处理时间过长,而导致中断丢失,把一些在中断处理中不是非常紧急的任务放在后面执行,让中断尽快返回。
下半部机制
softirq
Tasklets
Workqueues
上半部与下半部区别
指中单处理程序,下半部是可以延后执行任务。
static void tasklet_handler(unsigned logn value)
{
printk("tasklet_handler");
}
tasklet_stuct my_tasklet;
static unsigned long data=0;
tasklet_init(&my_tasklet,tasklet_handler,data);
tasklet_schedule(&my_tasklet);//放入调度队列
//依然处于中断上下文,但是开中断可以响应其他中断
还有工作队列workqueues,不是中断上下文
软中断和tasklet,workqueue
软中断不是马上可以执行,必须内核调度,不能被自己打断,只能被硬件中断打断
可以并发运行在多个cpu上,所以必须可重入,需要使用自旋锁来保护。
tasklet:
因为软中断必须可重入,有时候应用只需要单核,没必要设计重入,所以设计了tasklet
tasklet只能运行在一个cpu上,不能并行,只能串行
多个不同tasklet可以运行在多个cpu
软中断静态分配。
workqueue:
上面两个运行在中断上下文,导致不能睡眠阻塞,中断上下文在内核态,没有进程切换,所以如果中断睡眠阻塞无法退出,导致内核僵死,但可阻塞函数不能在中断上下文实现,必须在进程上下文,所以2.6版后内核,出现在内核运行的工作队列。