同步线程银行问题总结及解决

 操作系统用同步线程解决银行转账的典型问题,在做实验的时候遇到了很多问题,在这里记录一下解决办法,如果有遇到一样问题的人,希望这篇文章可以帮忙。(博主是在windows下做的)

同步机制及应用编程实现与比较实验功能设计要求:
(1) 银行账户转账同步问题的抽象及未采取同步控制情况下的编程
实现;
(2) 基于Peterson算法的银行账户转账问题解决方案;
(3) 基于Windows(Linux)操作系统同步机制的银行账户转账同步
问题解决方案;
(4)Peterson算法同步机制和Windows(或Linux)操作系统同步机制的效率比较。
这里,银行账户转账假定为两个账户nAccount1、nAccount2(均定义为初值是0的整性全局变量)之间进行,一个转出、一个转入,转账金额随机产生。整个程序共设立该两个账户之间的转账线程两个,且线程功能设计逻辑完全一致。

没有互斥的线程:
问题一:
 设置的count是1000,但是最后运行结束的时候循环只进行了不到10次,这合理吗?
在这里插入图片描述在这里插入图片描述
解决:
 答案当然是合理的。因为在没有互斥信号量的线程运行过程中,线程的执行的随机的,无法保证两个账户的和在每笔交易之后仍然是定值,因此程序在什么时候结束都是有可能的,循环执行多少次都是随机的。

同步机制
问题二:
 当循环次数设置到1000000次时,最后的输出结果中只看到了一个线程输出的循环次数,没有看到另一个,这是为什么呢?
在这里插入图片描述
解决:
 在windows操作系统的同步机制下线程的执行顺序时随机的,最后只能看到其中一个线程的结果,有可能是另一个线程在很早之前已经循环完1000000次结束了,已经输出过了结果。

peterson算法
问题三:
 最后的输出结果永远都是只差一个循环是为什么?
在这里插入图片描述
解决:
 这就是peterson算法的谦让。根据peterson算法的原理,只有在flag的值从1变到0的时候另一个线程才会开始执行,因为在循环的最后会执行flag值的变换操作,所以两个线程是交替执行的,也因此,最后输出结果之间一定会差一个循环。

一些小问题
1、如果设置了两个线程函数,需要使用两个nLoop来记录线程执行的次数。如果只有一个nLoop的话,在同步机制中,同时修改其值会发生错误。
2、使用互斥信号量mutex一定要初始化

HANDLE mutex = CreateMutex(NULL, FALSE, NULL);

3、peterson算法的主体部分放到线程函数的循环体中。

源代码

//Peterson算法
#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<time.h>
#define COUNT 1000000

int flag[2] = { 0, 0 };
int nLoop0 = 0, nLoop1 = 0;//转账次数
int nTemp1, nTemp2, nRandom;//账户临时存储1、2  转账随机数
int nAccount1 = 0, nAccount2 = 0;//账户1、2
int turn;

DWORD WINAPI Fun0(HANDLE Thread)
{
	do 
	{
		flag[0] = 1;
		turn = 1;
		while ((flag[turn] == 1) && (turn == 1));
		nRandom = rand() % 1000;
		nTemp1 = nAccount1;
		printf("nAccount1当前资金为:%d\n", nTemp1);
		nTemp2 = nAccount2;
		printf("nAccount2当前资金为:%d\n", nTemp2);
		nAccount1 = nTemp1 + nRandom;//账户1转入
		printf("nAccount1收到资金 %d,现资金为:%d\n", nRandom, nAccount1);
		nAccount2 = nTemp2 - nRandom;//账户2转出
		printf("nAccount2转出资金 %d,现资金为:%d\n", nRandom, nAccount2);
		nLoop0++;//转账次数+1
		flag[0] = 0;//解除另一个进程的使用限制
	} while (((nAccount1 + nAccount2) == 0) && (nLoop0 < COUNT));
	printf("Fun0循环次数为 %d 次\n", nLoop0);
	return 0;
}
DWORD WINAPI Fun1(HANDLE Thread)
{
	do
	{
		flag[1] = 1;
		turn = 0;
		while ((flag[turn] == 1) && (turn == 0));
		nRandom = rand() % 1000;
		nTemp1 = nAccount1;
		printf("nAccount1当前资金为:%d\n", nTemp1);
		nTemp2 = nAccount2;
		printf("nAccount2当前资金为:%d\n", nTemp2);
		nAccount1 = nTemp1 + nRandom;//账户1转入
		printf("nAccount1收到资金 %d,现资金为:%d\n", nRandom, nAccount1);
		nAccount2 = nTemp2 - nRandom;//账户2转出
		printf("nAccount2转出资金 %d,现资金为:%d\n", nRandom, nAccount2);
		nLoop1++;//转账次数+1
		flag[1] = 0;//解除另一个进程的使用限制
	}while (((nAccount1 + nAccount2) == 0) && (nLoop1 < COUNT));
	printf("Fun1循环次数为 %d 次\n", nLoop1);
	return 0;
}

int main()
{
	HANDLE Thread[2];
	DWORD starttime, endtime;
	starttime = GetTickCount();//开始时间
	Thread[0] = CreateThread(NULL, 0, Fun0, NULL, 0, NULL);//创建线程
	Thread[1] = CreateThread(NULL, 0, Fun1, NULL, 0, NULL);
	WaitForMultipleObjects(2, Thread, TRUE, INFINITE);//等待
	endtime = GetTickCount();//结束时间
	printf("运行时间为:%ld ms\n", endtime - starttime);
	CloseHandle(Thread[0]);//结束线程
	CloseHandle(Thread[1]);
	return 0;
}
//Windows
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#define COUNT 1000000

int nLoop0 = 0,nLoop1 = 0;//转账次数
int nTemp1, nTemp2, nRandom;//账户临时存储1、2  转账随机数
int nAccount1 = 0, nAccount2 = 0;//账户1、2
HANDLE mutex;

DWORD WINAPI Fun0(HANDLE Thread)
{
	do
	{
		WaitForSingleObject(mutex, INFINITE);
		nRandom = rand() % 1000;
		nTemp1 = nAccount1;
		printf("nAccount1当前资金为:%d\n", nTemp1);
		nTemp2 = nAccount2;
		printf("nAccount2当前资金为:%d\n", nTemp2);
		nAccount1 = nTemp1 + nRandom;//账户1转入
		printf("nAccount1收到资金 %d,现资金为:%d\n", nRandom, nAccount1);
		nAccount2 = nTemp2 - nRandom;//账户2转出
		printf("nAccount2转出资金 %d,现资金为:%d\n", nRandom, nAccount2);
		nLoop0++;//转账次数+1
		ReleaseMutex(mutex);
	} while (((nAccount1 + nAccount2) == 0) && (nLoop0 < COUNT));
	printf("Fun0循环次数为 %d 次\n", nLoop0);
	return 0;
}

DWORD WINAPI Fun1(HANDLE Thread)
{
	do
	{
		WaitForSingleObject(mutex, INFINITE);
		nRandom = rand() % 1000;
		nTemp1 = nAccount1;
		printf("nAccount1当前资金为:%d\n", nTemp1);
		nTemp2 = nAccount2;
		printf("nAccount2当前资金为:%d\n", nTemp2);
		nAccount1 = nTemp1 + nRandom;//账户1转入
		printf("&&&nAccount1收到资金 %d,现资金为:%d\n", nRandom, nAccount1);
		nAccount2 = nTemp2 - nRandom;//账户2转出
		printf("&&&nAccount2转出资金 %d,现资金为:%d\n", nRandom, nAccount2);
		nLoop1++;//转账次数+1
		ReleaseMutex(mutex);
	} while (((nAccount1 + nAccount2) == 0) && (nLoop1 < COUNT));
	printf("Fun1循环次数为 %d 次\n", nLoop1);
	return 0;
}

int main()
{
	HANDLE Thread[2];
	DWORD starttime, endtime;
	starttime = GetTickCount();
	mutex = CreateMutex(NULL, FALSE, NULL);
	Thread[0] = CreateThread(NULL, 0, Fun0, NULL, 0, NULL);//创建线程函数
	Thread[1] = CreateThread(NULL, 0, Fun1, NULL, 0, NULL);
	WaitForMultipleObjects(2, Thread, TRUE, INFINITE);//等待
	endtime = GetTickCount();
	printf("运行时间为:%ld ms\n", endtime - starttime);
	CloseHandle(Thread[0]);//结束线程
	CloseHandle(Thread[1]);
	return 0;
}
//Windows无互斥
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#define COUNT 100

int nLoop0 = 0,nLoop1 = 0;//转账次数
int nTemp1, nTemp2, nRandom;//账户临时存储1、2  转账随机数
int nAccount1 = 0, nAccount2 = 0;//账户1、2

DWORD WINAPI Fun0(HANDLE Thread)
{
	do
	{
		nRandom = rand() % 1000;
		nTemp1 = nAccount1;
		printf("nAccount1当前资金为:%d\n", nTemp1);
		nTemp2 = nAccount2;
		printf("nAccount2当前资金为:%d\n", nTemp2);
		nAccount1 = nTemp1 + nRandom;//账户1转入
		printf("nAccount1收到资金 %d,现资金为:%d\n", nRandom, nAccount1);
		nAccount2 = nTemp2 - nRandom;//账户2转出
		printf("nAccount2转出资金 %d,现资金为:%d\n", nRandom, nAccount2);
		nLoop0++;//转账次数+1
	} while (((nAccount1 + nAccount2) == 0) && (nLoop0 < COUNT));
	printf("Fun0循环次数为 %d 次\n", nLoop0);
	return 0;
}

DWORD WINAPI Fun1(HANDLE Thread)
{
	do
	{
		nRandom = rand() % 1000;
		nTemp1 = nAccount1;
		printf("nAccount1当前资金为:%d\n", nTemp1);
		nTemp2 = nAccount2;
		printf("nAccount2当前资金为:%d\n", nTemp2);
		nAccount1 = nTemp1 + nRandom;//账户1转入
		printf("nAccount1收到资金 %d,现资金为:%d\n", nRandom, nAccount1);
		nAccount2 = nTemp2 - nRandom;//账户2转出
		printf("nAccount2转出资金 %d,现资金为:%d\n", nRandom, nAccount2);
		nLoop1++;//转账次数+1
	} while (((nAccount1 + nAccount2) == 0) && (nLoop1 < COUNT));
	printf("Fun1循环次数为 %d 次\n", nLoop1);
	return 0;
}

int main()
{
	HANDLE Thread[2];
	DWORD starttime, endtime;
	starttime = GetTickCount();
	Thread[0] = CreateThread(NULL, 0, Fun0, NULL, 0, NULL);//创建线程函数
	Thread[1] = CreateThread(NULL, 0, Fun1, NULL, 0, NULL);
	WaitForMultipleObjects(2, Thread, TRUE, INFINITE);//等待
	endtime = GetTickCount();
	printf("运行时间为:%ld ms\n", endtime - starttime);
	CloseHandle(Thread[0]);//结束线程
	CloseHandle(Thread[1]);
	return 0;
}
  • 5
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值