的同步和互斥问题。
使用3 个信号量,其中两个信号量 avail 和 full 分别用于解决生产者和消费者线程 之间的同步问题,mutex 是用于这两个线程之间的互斥问题。其中 avail 表示有界缓冲区中 的空单元数,初始值为 N;full 表示有界缓冲区中非空单元数,初始值为 0;mutex是互斥 信号量,初始值为 1。参考流程图如图2所示。
开始 建立有名管道 打开有名管道 初始化三个信号量 创建消费者和生 产者两个线程 生产者线程 P操作(avail) P操作(mutex) 读管道消费者线程 P操作(full) P操作(mutex) 写管道 V操作(full) V操作(mutex) 结束 V操作(avail) V操作 ) (mutex 图2 多线程实验流程图
三、实验步骤
1、根据参考流程图编写程序;
2、编译和运行程序代码,并观察运行结果。
6
实验3 模块编程实验
实验序号:3 适用专业:计算机科学与技术、通信工程 一、实验目的
1、熟悉模块添加和删除的方法。 2、熟悉字符设备驱动的编写流程。 二、实验内容
要求实现到虚拟设备(一段内存)的打开、关闭、读写的操作,并通过编写测试程序来
实验名称:模块编程实验 学 时 数:4学时
测试虚拟设备及其驱动运行是否正常。 三、实验步骤
(1)编写代码。
这个简单的驱动程序的源代码如下所示: /*test_drv.c*/
#include
#define TEST_DEVICE_NAME “test_dev” #define BUFF_SZ 1024 /*全局变量*/
static struct cdev test_dev; unsigned int major=250; static char *data=NULL; /*读函数*/
static ssize_t test_read(struct file *file,char *buf,size_t count, loff_t
*f_pos)
{
int len; if (count<0)
7
}
{ }
len=strlen(data);
count=(len>count)?count:len;
if (copy_to_user(buf,data,count)) /*将内核缓冲的数据复制到用户空间*/ { }
return count;
return –EFAULT; return –EINVAL;
/*写函数*/
static ssize_t test_write(struct file *file,const char *buffer,size_t count,loff_t *f_pos) {
if(count<0) { }
memset(data,0,BUFF_SZ); }
/*打开函数*/
static int test_open(struct inode *inode,struct file *file) {
printk(“This is open operation\\n”); /*分配并初始化缓冲区*/
data= (char*)kmalloc(sizeof(char)* BUFF_SZ,GFP_KERNEL); if(!data)
count=(BUFF_SZ>count)?count:BUFF_SZ;
if(copy_from_user(data,buffer,count)) /*将用户缓冲的数据复制到内核空间*/ { }
return count;
return –EFAULT; return –EINVAL;
8
}
{ }
memset(data,0,BUFF_SZ); return 0;
return –ENOMEM;
/*关闭函数*/
static int test_release(struct inode *inode,struct file *file) { }
/* 创建、初始化字符设备,并且注册到系统*/
static void test_setup_cdev(struct cdev *dev, int minor,
struct file_operations *fops)
{
int err, devno = MKDEV(major, minor); cdev_init(dev, fops); dev->owner = THIS_MODULE; dev->ops = fops;
err = cdev_add (dev, devno, 1);
if (err) {
printk (KERN_NOTICE \}
} /* 虚拟设备的 file_operations 结构 */
static struct file_operations test_fops = {
.owner = THIS_MODULE,
.read .open };
/*模块注册入口*/
9
= test_read, = test_open,
.write = test_write, .release = test_release,
printk(“This is release operation\\n”); if(data) { } return 0;
kfree(data); data=NULL;
/*释放缓冲区*/ /*防止出现野指针*/
int init_module(void) {
int result;
dev_t dev = MKDEV(major, 0); if (major)
{/* 静态注册一个设备,设备号先前指定好,并设定设备名,用 cat /proc/devices 来查看*/ } else { }
if(result<0) {
printk(KERN_WARNING\return result;
}
test_setup_cdev(&test_dev, 0, &test_fops);
printk(\return 0; }
/*卸载模块*/
void cleanup_module(void) {
cdev_del(&test_dev);
unregister_chrdev_region(MKDEV(major, 0), 1); printk(\}
result=alloc_chrdev_region(&dev,0,1,TEST_DEVICE_NAME); result=register_chrdev_region(dev,1,TEST_DEVICE_NAME);
(2)编译代码。
虚拟设备的驱动程序的 Makefile 如下所示:
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build /*内核代码编译路径*/ PWD := $(shell pwd) modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions .PHONY: modules modules_install clean else
obj-m := test_drv.o
/* 将生成的模块为 test_drv.ko*/
10