历史上的今天
返回首页

历史上的今天

今天是:2024年12月31日(星期二)

正在发生

2021年12月31日 | 4412 并发

2021-12-31 来源:eefocus

一、并发基本概念

1.并发

  • 并发的概念是:多个执行单元同时、并行被执行

  • Linux系统是多任务的,很多任务会同时执行

  • 假如有三个执行单元ABC,共享了内存资源

    • 执行单元A对Buffer写1000个"a";

    • 执行单元B对Buffer写1000个"b";

    • 执行单元C从Buffer中读取数据。

    • 如果按照A写→C读→B写→C读,当然没有问题。

    • 但是如果A写→B写→C读,执行单元C就出问题了。

  • 当然比这个复杂更多,更加混乱的并发操作存在设备驱动中。

  • 只要有多个进程对共享资源的同时访问,就可能出现竞争。

2.竞态

  • 以下三种情况会导致竞态

  • 对称多处理的多个CPU

  • 单CPU内进程和强占它的进程

  • 中断和进程

3.竞态的解决办法

  • 解决竞态的途径是“保证对共享资源的互斥访问”

  • 也就是一个执行单元在访问共享资源的时候,其他的执行单元被禁止访问。

  • 访问共享资源的代码区称为临界区,临界区需要使用互斥机制来保护。

4.Linux操作系统中提供实现互斥的方法

  • 原子操作、自旋锁、信号量、互斥体等。

  • 后续视频介绍原子操作,自旋锁,互斥体

 

二、并发控制之原子操作

1.直接列出内核中提供的宏定义

解决竞态的途径是"保证对共享资源的互斥访问"

  • 变量:atomic_t 整型变量

  • 宏定义:atomic_read    (*(volatile int *)&(v)->counter)

    • volatile关键词:表示变量每次被访问,执行单元每次从内存单元中取值。

    • 不带关键词:表示变量在编译的时候可能被"优化"。(可能是CPU内部寄存器)

    • 保证对特殊地址的稳定访问!

  • 宏定义:atomic_inc  atomic_add(1, (v))  变量加1

  • 宏定义:atomic_dec        变量减1

  • 宏定义:ATOMIC_INIT        赋值

 2.如何使用

假设任务单元A第一个申请"共享单元"。则先读变量,如果0,则对变量加1,然后对共享资源进行操作。操作完毕之后对变量赋值。

假设任务单元B要申请"共享单元"。则先读变量,如果0,则对变量加1,然后对共享资源进行操作。操作完毕之后对变量赋值。如果为1,直接返回。

3.代码分析

open_atomic_int_one以及open_atomic_int_two两个程序

要对/dev/atomic_int设备节点镜像操作

先运行的程序,将变量赋值为1,释放的时候赋值为0

如果程序1在没有释放的情况下,程序2调用设备节点则会直接返回,无法调用。

如果程序1在在没有释放的情况下,程序2调用则会直接返回,无法调用。

atomic

#include

#include


/* device register */

#include

/* register misc device */

#include

/* register device node */

#include

/* atomic */

#include

#include


#define DRIVER_NAME "atomic_int"

#define DEVICE_NAME "atomic_int"


MODULE_LICENSE("Dual BSD/GPL");

MODULE_AUTHOR("Topeet");


static atomic_t value_atomic = ATOMIC_INIT(0);


static int atomic_int_open(struct inode *inode, struct file *file)

{

        printk(KERN_EMERG "atomic_int open in!n");


        if(atomic_read(&value_atomic)) {

                return -EBUSY;

        }


        atomic_inc(&value_atomic);


        printk(KERN_EMERG "atomic_int open success!n");

        return 0;

}


static int atomic_int_release(struct inode *inode, struct file *file)

{

        printk(KERN_EMERG "atomic_int releasen");


        atomic_dec(&value_atomic);


        return 0;

}


static struct file_operations atomic_int_ops = {

        .owner = THIS_MODULE,

        .open = atomic_int_open,

        .release = atomic_int_release,

};


static struct miscdevice atomic_int_dev = {

        .minor = MISC_DYNAMIC_MINOR,

        .name = DEVICE_NAME,

        .fops = &atomic_int_ops,

};


static int atomic_int_probe(struct platfrom_device *pdv)

{

        printk(KERN_EMERG "tinitalizedn");

        misc_register(&atomic_int_dev);


        return 0;

}


static int atomic_int_remove(struct platform_device *pdv)

{

        printk(KERN_EMERG "tremvoen");

        misc_deregister(&atomic_int_dev);


        return 0;

}


struct platform_driver atomic_int_driver = {

        .probe = atomic_int_probe,

        .remove = atomic_int_remove,

        .driver = {

                .name = DRIVER_NAME,

                .owner = THIS_MODULE,

        }

};


static int atomic_int_init(void)

{

        int DriverState;


        printk(KERN_EMERG "atomic int entern");

        DriverState = platform_driver_register(&atomic_int_driver);


        printk(KERN_EMERG "tDriverState is %dn", DriverState);

        return 0;

}


static void atomic_int_exit(void)

{

        printk(KERN_EMERG "atomic int exitn");


        platform_driver_unregister(&atomic_int_driver);

}


module_init(atomic_int_init);

module_exit(atomic_int_exit);


open_one:

#include


#include

#include

#include

#include

#include


int main(int argc, char *argv[])

{

        char *atomic_int = "/dev/atomic_int";

        int fd;


        if((fd = open(atomic_int, O_RDWR|O_NDELAY)) < 0) {

                printf("%s open %s fialed!n", argv[0], atomic_int);

        } else {

                printf("%s open %s success!n", argv[0], atomic_int);

        }


        while(1);

}


opne_two:

#include


#include

#include

#include

#include

#include


int main(int argc, char *argv[])

{

        char *atomic_int = "/dev/atomic_int";

        int fd;


        if((fd = open(atomic_int, O_RDWR|O_NDELAY)) < 0) {

                printf("%s open %s fialed!n", argv[0], atomic_int);

        } else {

                printf("%s open %s success!n", argv[0], atomic_int);

        }


        while(1);

}

 

4.测试结果

[root@iTOP-4412]# insmod atomic.ko                                                     

[   69.905118] atomic int enter

[   69.906830]  initalized

[   69.925677]  DriverState is 0

[root@iTOP-4412]# ls /dev/atomic_int -l                                                

crw-rw----    1 root     0          10,  47 Jan  1 01:47 /dev/atomic_in


[root@iTOP-4412]# ./open_atomic_int_one &                                              

[root@iTOP-4412]# [   83.577155] atomic_int open in!

[   83.578851] atomic_int open success!

./open_atomic_int_one open /dev/atomic_int sucess!


[root@iTOP-4412]# ./open_atomic_int_two                                                

[   92.529032] atomic_int open in!

./open_atomic_int_two open /dev/atomic_int failed!


[root@iTOP-4412]# kill 1659                                                            

[root@iTOP-4412]#[  115.020445] atomic_int release

 

[1]+  Terminated                 ./open_atomic_int_one

[root@iTOP-4412]# ./open_atomic_int_two                                                

[  120.023368] atomic_int open in!

[  120.025137] atomic_int open success!

./open_atomic_int_two open /dev/atomic_int sucess!


^C[  123.292457] atomic_int release


遇到的问题:

一开始注册,没有运行probe函数。所以需要对内核裁剪(driver/char/Kconfig和arch/arm/mach-exynos/mach-top4412.c的修改)。

增减ATOMIC_INT_CONFIG,并编译内核后烧录。

 

三、并发控制之位原子操作

1.直接列出内核中提供的宏定义

宏定义:test_bit 返回位原子值

宏定义:set_bit 设置位

宏定义:clear_bit 清除位

 

2.如果使用

类似整型的原子操作

 

3.代码分析

  • open_atomic_bit_two以及open_atomic_bit_one两个程序

  • 要对/dev/atomic_bit这个设备节点进行操作

  • 先运行open之后,将变量赋值为1,释放的时候赋值为0

  • 如果在其中一个程序调用的过程中没有释放,第二个程序要对节点操作,则会直接返回错误。

 测试代码:

atomic_bit

#include

#include


/* device register */

#include

/* register misc device */

#include

/* register device node */

#include

/* atomic */

#include

#include


#define DRIVER_NAME "atomic_bit"

#define DEVICE_NAME "atomic_bit"


MODULE_LICENSE("Dual BSD/GPL");

MODULE_AUTHOR("Topeet");


//static atomic_t value_atomic = ATOMIC_INIT(0);

unsigned long int value_bit = 0;


static int atomic_bit_open(struct inode *inode, struct file *file)

{

        printk(KERN_EMERG "atomic_int open in!n");

/*

        if(atomic_read(&value_atomic)) {

                return -EBUSY;

        }


        atomic_inc(&value_atomic);

*/

        if(test_bit(0, &value_bit) != 0) {

                return -EBUSY;

        }


        set_bit(0, &value_bit);


        printk(KERN_EMERG "atomic_int open success!n");

        return 0;

}


static int atomic_bit_release(struct inode *inode, struct file *file)

{

        printk(KERN_EMERG "atomic_int releasen");


        //atomic_dec(&value_atomic);


        clear_bit(0, &value_bit);


        return 0;

}


static struct file_operations atomic_bit_ops = {

        .owner = THIS_MODULE,

推荐阅读

史海拾趣

Cressall Power Resistors公司的发展小趣事

在电子行业的早期,Cressall Power Resistors公司以其对电阻技术的深入研究而脱颖而出。公司研发团队通过不懈的努力,成功开发出一种新型的功率电阻器,具有更高的耐热性、更低的电阻值变化率以及更长的使用寿命。这一技术突破迅速得到了市场的认可,公司因此获得了大量的订单,业绩迅速增长。随着技术的不断完善和产品的持续升级,Cressall逐渐在功率电阻器市场树立了技术领先的地位。

硕颉(BITEK)公司的发展小趣事

尽管硕颉科技在知识产权方面做出了积极努力,但仍难免面临专利诉讼的挑战。在某次与凹凸科技的专利侵权诉讼中,公司虽然一度面临败诉和永久禁制令的风险,但硕颉科技迅速应诉,积极应对。最终,美国联邦巡回上诉法院废除了原判决,公司得以自由销售被诉产品,不受任何限制。这次诉讼的胜利,不仅展示了硕颉科技在应对法律挑战方面的决心和能力,也为公司的长远发展奠定了坚实基础。

Daniels Manufacturing公司的发展小趣事

自1946年成立以来,Daniels Manufacturing Corporation一直致力于为军事和电信行业提供高质量的工具系统和技术。在20世纪70年代,DMC经历了一次重大的技术突破,成功研发出一种新型的手动压接工具,该工具能够精确、高效地处理各种电子连接器。这一技术的突破为DMC赢得了市场的认可,也为其后续的产品线扩展奠定了基础。在接下来的几十年里,DMC不断投入研发,推出了包括电动、气动、液压压接工具在内的多种产品,广泛应用于通信、光纤、激光等领域。

Fermionics Lasertech Inc公司的发展小趣事

面对日益激烈的市场竞争,Fermionics Lasertech Inc公司始终坚持以创新为驱动力。他们不断投入研发资金,引进高端人才,加强与高校和科研机构的合作,共同推动激光技术的创新。公司成功研发出了一系列具有自主知识产权的新型激光器,不仅提升了产品性能,还降低了生产成本,使公司在激烈的市场竞争中保持领先地位。

Delphi Connection Systems公司的发展小趣事

Delphi Connection Systems公司自创立之初,就致力于在电子行业中的连接器技术上进行创新。公司投入大量研发资源,开发出一种新型的高性能连接器,这种连接器具有更小的体积、更高的可靠性和更低的传输损耗。这一创新成果迅速获得了市场的认可,为公司带来了大量的订单和合作机会。

Axiomtek公司的发展小趣事

随着市场的不断发展,Delphi Connection Systems公司意识到单靠自身的力量难以在激烈的市场竞争中立足。于是,公司积极寻求与其他企业的战略合作,通过资源共享、优势互补,共同开拓市场。公司与一家知名的汽车制造商建立了战略合作关系,为其提供高质量的连接器产品,从而成功进入了汽车电子行业市场。

问答坊 | AI 解惑

数控机床的机械结构的要求

在数控机床发展的最初阶段,其机械结构与通用机床相比没有多大的变化,只是在自动变速、刀架和工作台自动转位和手柄操作等方面作些改变。随着数控技术的发展,考虑到它的控制方式和使用特点,才对机床的生产率、加工精度和寿命提出了更高的要求。数 ...…

查看全部问答>

谁能告诉我,电压比较器成本?

各位朋友,在制作各种电压检测的产品中,少不了电压取样和比较,常用的比较多,老板为了降成本,所以目前的电压比较器都不能用,(成本原因)要求比较器灵敏度在2mV以下,工作电流小于0.5mA以下,工作电压3-20V,要求成本不超过0.1元人民币,目前国 ...…

查看全部问答>

三极管问答

本帖最后由 paulhyde 于 2014-9-15 03:34 编辑 三极管问答 [ 本帖最后由 yushiqian 于 2009-8-15 23:33 编辑 ]    …

查看全部问答>

USB转并口

我的本子上只有usb口,想买个430的学习板,可是430的usb下载线太贵了!请问有没有可以用的usb转并口啊?…

查看全部问答>

高密度电源的工艺设计(看看什么叫牛!140mm*44mm*90mm做到5000W)

高密度电源的工艺设计(看看什么叫牛!140mm*44mm*90mm做到5000W)    在网上看到“斜阳古道”大哥发了篇“高密度电源的工艺设计”,看了之后简直是叹服!拿出来与大家分享。在网上找了半天也没找到原理图什么的, ...…

查看全部问答>

温度传感器出现的问题

最近公司里两台热辊里的温度传感器出现一个偏高(实测126℃),一个偏低(实测121℃),后来把两个温度传感器交换了一下,两个传感器都变成了123℃,可能是什么原因?温度传感器后面有个放大器。…

查看全部问答>

南通大富豪

海安团购网网站:http://www.haiantuangou.com/         www.8880513.com 亲爱的朋友,你还在喜欢玩斗地主吗,你还在玩那些没钱赚的网页斗地主吗,你也梦想有一天能日赚千元吗?只要有梦想,你就能实现,在这里我 ...…

查看全部问答>

AVR单片机问与答

来自维库人才网     问:我想使用AVR 单片机中的Mega 系列,有哪些开发工具支持这种单片机?   答AVR 单片机中的Mega 系列有一套完善的开发工具评估/编程板ATMEL 的 STK500(980 元/套)起步工具包是适用于开发Atmega103 芯片的对芯片 ...…

查看全部问答>

求,怎样在51中放置一串数据,掉电数据不丢失

在51单片机中放置一串十几字节的数据,掉电以后数据不丢失,上电以后可以再次读出这个数据, 请问这个数据放在哪里的呢? 怎样用C或者汇编来放这些数据呢? 还有就是怎样对它进行读写?…

查看全部问答>

关于Intel IPP库使用问题

大侠们好。 最近做有关MPEG4编解码的项目,用的是Intel PXA270处理器。现在发现编码程序的代码中 mp4emblk.c里ippiCopyBlock_8x8_8u和ippiReconBlock_8x8这两个函数不能够链接。也就是说Intel IPP库里面没有这两个函数。 我下的IPP版本是5.0的。 ...…

查看全部问答>