一、软件法
1.轮转法
p0 进程:
while(turn != 0); //进入区
critical section ; //临界区
turn = 1; //退出区
remainder section; //剩余区
p1进程:
while(turn != 1); //进入区
critical section; //临界区
turn = 0; //退出区
remainder section; //剩余区
---------------------
作者:李永贵
来源:CSDN
原文:https://blog.csdn.net/lierming__/article/details/78974244
版权声明:本文为博主原创文章,转载请附上博文链接!
2.标志法
3.Perterson算法
Pi 进程:
flag[i] = TRUE; turn = j; //进入区
while(flag[j] && turn == j); //进入区
critical section; //临界区
flag[i] = FALSE ; //退出区
remainder section; //剩余区
Pj 进程:
flag[j] = TRUE; turn = i; //进入区
while(flag[i] && turn == i); //进入区
critical section; //临界区
flag[j] = FALSE; //退出区
remainder section; //剩余区
---------------------
作者:李永贵
来源:CSDN
原文:https://blog.csdn.net/lierming__/article/details/78974244
版权声明:本文为博主原创文章,转载请附上博文链接!
软件方法看似从逻辑上实现了互斥,但隐含条件是对共享标志变量的写和读需要在一条指令内完成,否则对标志的访问本身就会造成错误。例如,在Perterson算法中,若CPU为8位,turn为16位变量,则对标志变量的存取至少需要2条指令,如果一个任务先对turn写了低8位,然后切换到另一个任务完整的写了turn,再切换回去写了高8位,那么turn的值是无法预测的。
所以所谓软件方法要完全实现保护,也是需要和硬件特性相关的,实际上用汇编实现才能绝对正确。个人觉得完全不如下面的硬件法。
二、硬件法
1.利用硬件原子指令
2.关闭中断
3.关闭任务调度
4.利用信号量
(3和4实际上是有操作系统时,操作系统用其他方法实现的封装)
三、方法总结
1.单片机裸机编程
在单片机裸机编程时,出现的情况常常是在中断中获取数据,然后在后台循环中进行数据处理,我思考得到的方法伪代码如下:
//主函数
void main()
{
while(1)
{
...
intClose(); //关中断
if(flag==true) //标志为真
{
... //处理数据(操作尽量少,一般只是把数据移到局部变量中)
flag=false;
}
intOpen(); //开中断
...
}
}
//中断处理函数
void interrupt()
{
//加上判断时若数据未处理则不再接收,可不加判断使数据未处理时接收新数据覆盖
if(flag==false)
{
... //接收数据
flag=true;
}
}
2.操作系统编程
在操作系统上编程主要使用信号量,我想到的信号量PV操作可以用如下伪代码实现
void P(sem)
{
int temp;
intClose(); //关中断
sem--; //信号量减一
temp = sem; //用局部变量保存信号量
intOpen(); //开中断
if(temp < 0)
{
sleep(); //阻塞自身进程
}
}
void V(sem)
{
int temp;
intClose(); //关中断
sem++; //信号量加一
temp = sem; //用局部变量保存信号量
intOpen(); //开中断
if(temp <= 0)
{
wake(); //从阻塞序列中唤醒进程
}
}
信号量可以实现共享资源的保护(线程锁)和任务同步,使用时应该遵循一定规则避免程序长时间非正常阻塞,通常是锁操作在同步操作的内部,伪代码如下:
datatype data; //共享变量
void taskSend() //发送任务
{
datatype buff;
while(1)
{
....... //操作
pthread_mutex_lock();
data = buff;
pthread_mutex_unlock();
sem_post();
}
}
void taskReceive() //接收任务
{
datatype buff;
while(1)
{
sem_wait();
pthread_mutex_lock();
buff = data;
pthread_mutex_unlock();
....... //操作
}
}
其中,如果data缓存大小比每次需要传输的大,就可以不用加锁。消息队列可以实现缓存和信号同步的功能。
(以上内容均为自己思考所得,如有错误和疏漏,感谢大家指正)