多线程和多核芯片( 三 )


定义:俩个或多个线程同时对一共享数据进行修改,从而影响程序运行的正确性,这种就被称为 竞态条件 。
临界区
如何对竞态条件避免?
禁止一个或多个进程在同一时刻对共享资源(共享内存、共享文件)进行读写 。
需要设定互斥条件 。除该进程之外的其他进程禁止访问共享资源 。
我们把对共享内存进行访问的程序片称为 临界区 。使俩个不同进程不可能处于临界区,即可避免竞争条件 。
忙等互斥 屏蔽中断
在单处理器系统上,最简单的解决方案是,让每个进程在进入临界区后 立即 屏蔽所有中断,并在离开临界区之前重新启用 。
锁变量
单个共享的(锁)变量,初始值为0 。
当一个线程想要进入关键区域时,先看锁的值是否为0,如果是0,进程将其设置为1,之后再进入关键区域,若锁的值为1,那么进程将会一直等待锁变量变为0.
严格轮询法
该方法违反了:位于临界区外的进程不得阻塞其他进程,进程0被一个临界区外的进程阻塞,所以不太行 。
解法
#define FALSE 0#define TRUE 1/*进程数量*/#define N 2 /* 现在轮到谁 */int turn; /* 所有值都初始化为 0 (FALSE) */int interested[N]; /* 进程时 0 或 1 */void enter_region(int process){ /* 另一个进程号 */ int other; /* 另一个进程 */ other = 1 - process; /* 表示愿意进入临界区 */interested[process] = TRUE; turn = process;/*空循环*/while(turn == process&& interested[other] == true){}}void leave_region(int process){/* 离开临界区 */interested[process] == FALSE; }
TSL、XCHG指令
TSL RX,LOCK
测试并加锁 。
睡眠与唤醒–生产者-消费者问题
、TSL、 XCHG都有忙等待的缺点 。浪费了CPU的时间 。
所以采用 sleep 和 .
sleep:造成调用阻塞 。
:唤醒线程 。
生产者-消费者问题 也称 有界缓冲区问题
【多线程和多核芯片】生产者:将信息放入缓存区 。
消费者:将信息从缓存区取出 。
M个生产者和N个消费者问题 。需要监听变量,用来监视缓冲区数据 。
/* 缓冲区slot槽的数量 */#define N 100 /* 缓冲区数据的数量*/int count = 0 // 生产者void producer(void){int item;/* 无限循环 */while(TRUE){ /* 生成下一项数据 */item = produce_item() /* 如果缓存区是满的,就会阻塞 */if(count == N){sleep(); }/* 把当前数据放缓冲区中 */insert_item(item);/* ?增加缓冲区数量*/count = count + 1; if(count == 1){/*判断是否为空*/wakeup(consumer); }}}// 消费者void consumer(void){int item;/* 无限循环*/while(TRUE){/* 如果缓存区是空的就会阻塞*/if(count == 0){sleep();}/* 从缓存区中取数据 */item = remove_item(); /* 减少缓存区监听到的数量 */count = count - 1/* 判断是否是满的 */ if(count == N - 1){ wakeup(producer); }/* 答应数据项*/ consumer_item(item); }}
会产生唤醒丢失问题,需要增加 唤醒等待位
信号量
解决唤醒丢失问题 。
互斥量
管程 调度
调度算法分类 批处理交互式实时
调度算法的目标:
批处理系统:
批处理系统中的调度 先来先服务
短作业优先
在所有进程都可以运行的情况下才能使用短作业优先。
交互式系统中中的调度 轮询调度
开销特别大!!
优先级调度
每个进程都被赋予了一个优先级,优先级高的进程先运行 。
多级队列(也是一种优先级调度) 最短进程优先