操作系统——笔记day8

并发中,解决数据同步的方法

方法一:原子操作

把a++变成原子操作,要么不执行,要么一口气执行完

实现原子操作无法依赖编译器,需要我们自己动手,x86有很多原子指令,我们只需要直接应用这些指令,用汇编代码写出对应的原子操作函数就可,而现代C语言已经支持嵌入汇编代码,所以在C函数中可以按照特定的方式嵌入汇编代码,实现原子操作

//定义一个原子类型
typedef struct s_ATOMIC{
    volatile s32_t a_count;
}atomic_t;
//原子读
static inline s32_t atomic_read(const atomic_t *v)
{
    return (*(volatile u32_t*)&(v)->a_count);
}
//原子写
static inline void atomic_write(atomic_t *v,int i)
{
    v->a_count = i;
}
//原子加上一个整数
static inline void atomic_add(int i,atomic_t *v)
{
    __asm__ __volatile__("lock;" "addl %1,%0"
                        :"+m"(v->a_count)
                        :"ir"(i));
}
//原子减去一个整数
static inline void atomic_sub(int i,atomic_t *v)
{
    __asm__ __volatile__("lock;" "subl %1,%0"
                        :"+m"(v->a_count)
                        :"ir"(i));
}
//原子加1
static inline void atomic_inc(atomic_t *v)
{
    __asm__ __volatile__("lock;" "incl%0"
                        :"+m"(v->a_count));
}
//原子减1
static inline void atomic_dec(atomic_t *v)
{
    __asm__ __volatile__("lock;" "decl %0"
                        :"+m"(v->a_count));
}

以上代码中,加上lock前缀的addl,subl,incl,decl指令都是原子操作,lock前缀表示锁定总线

GCC设计了一种特有的嵌入方式,规定了汇编代码嵌入的形式和嵌入汇编代码需要哪几部分

__asm__ __volatile__(代码部分:输出部分列表:输入部分列表:损坏部分列表);

括号里大致分为4部分:

1.汇编代码部分,实际嵌入的汇编代码

2.输出列表部分,让GCC能够处理C语言左值表达式与汇编代码的结合

3.输入列表部分,让GCC能够处理C语言表达式、变量、常量,让它们能够输入到汇编代码中

4.损坏列表部分,告诉GCC汇编代码中用到了哪些寄存器,以便GCC在汇编代码运行前,生成保存他们的代码

方法二:中断控制 搞定复杂变量

方法三:自旋锁 协调多核心CPU

自旋锁原理,首先读取锁变量,判断其值是否已经加锁,如果未加锁则执行加锁,然后返回,表示加锁成功;如果已经加锁,就要返回第一部继续执行后续步骤

要正确的执行它,就必须保证读取锁变量和判断并加锁的操作是原子执行的

x86有一个原子交换指令,xchg,它可以让寄存器里的一个值跟内存空间中的一个值做交换

方法四:信号量CPU时间管理

等待,互斥,唤醒

信号量的使用步骤

一、获取信号量

1.首先开启自旋锁保护信号量

2.对信号量计数值执行“加一”操作,并检查是否大于0

3.小于0,让进程进入等待状态并且将其挂入wait中,然后调度其他进程运行。否则表示信号量获取成功,然后解锁

二、代码执行流开始执行相关操作,入读取键盘缓冲区

三、释放信号量

1.加自旋锁保护信号量

2.对信号量计数值“加一”,并检查是否大于零

3.大于0唤醒wait中的进程

上一篇:使用XmlSerializer写文件


下一篇:序列化、反序列化,干啥用?