部分代码转自https://blog.csdn.net/yrx0619/article/details/79383252
Peterson算法目的是找到一个办法,当两个线程操作同一个资源时(比如一个读,一个写),避免冲突。读的线程执行读操作时,写线程不能对资源进行写操作;反之亦然。
最朴素的想法,建立两个全局变量,分别表征线程1和线程2对资源的占用情况。当线程1占用资源时,线程2不得占用之;当线程2占用资源时,线程1不得占用之。于是有了下面的代码:
#define FALSE 0
#define TRUE 1
#define N 2 // 进程数量
int own[N]; // 线程自维护数据,初始化为FALSE
void enter_region( int threadId ) // 线程号,取值为0,1
{
int other = 1 - threadId; // 代表另外的那个线程的号
own[threadId] = TRUE; // 设置当前线程的意向值为TURE
while( own[other] == TURE ); // 当互斥条件不满足即while里面的条件满足时忙等待
}
void leave_region( int threadId )
{
own[threadId] = FALSE; // 设置意向值表示不感兴趣
}
上述代码的想法是,利用own[2]作为线程占用资源的标记,每次线程要占用资源时,就把标记设置为true,然后等待与它竞争的线程退出,也就是把own[other]设置为false。当另一个线程放弃对资源的占有后,等待的线程走过while循环,得以处理资源。竞争线程再想占据资源,必须等待own[] = false.
但是,这个方案有个缺点:对于任何一个线程,在设置own[threadId] = true 和 等待while()之间,另一个线程可能刚好也完成了设置own[threadId] = true;于是两个线程都在等待对方释放资源标记,形成死锁。
这样一来,设置标记与等待之间的结合部就成了这个方案的软肋。Peterson算法的巧妙在于,又增加一个全局变量share:即使两线程恰好在软肋处冲突,share变量总会阻止一个而放过另一个 -- share的取值最终由晚到的那个线程决定。晚到的线程反而通过设置share释放了与之竞争的线程。
#define FALSE 0
#define TRUE 1 #define N 2 // 进程数量
int share; // 公共标记
int own[N]; // 线程自维护数据,初始化为FALSE
void enter_region( int threadId ) // 线程号,取值为0,1
{
int other = 1 - threadId; // 代表另外的那个线程的号
own[threadId] = TRUE; // 设置当前线程的意向值为TURE
share = threadId; // 设置标志位
while( share == threadId && own[other] == TURE ); // 当互斥条件不满足即while里面的条件满足时忙等待
}
void leave_region( int threadId )
{
own[threadId] = FALSE; // 设置意向值表示不感兴趣
}
---------------------
作者:yrx0619
来源:CSDN
原文:https://blog.csdn.net/yrx0619/article/details/79383252
版权声明:本文为博主原创文章,转载请附上博文链接!
以上的写法与下面的效果应该是一样的:(Open Question?)
#define FALSE 0
#define TRUE 1 #define N 2 // 进程数量
int share; // 公共标记
int own[N]; // 线程自维护数据,初始化为FALSE
void enter_region( int threadId ) // 线程号,取值为0,1
{
int other = 1 - threadId; // 代表另外的那个线程的号
own[threadId] = TRUE; // 设置当前线程的意向值为TURE
share = threadId; // 设置标志位
while( own[other] == TURE ) // 当互斥条件不满足即while里面的条件满足时忙等待
{
if(share != threadId)
{
break;
}
}
}
void leave_region( int threadId )
{
own[threadId] = FALSE; // 设置意向值表示不感兴趣
}