2021/11/1 paradigm 笔记

1 读写循环队列问题

2 哲学家问题

  • busy waiting
    忙等待
  • critical region
    临界区域
  • concurrency
    critical region 具有 “concurrency” 并发性
  • resource contention
    临界区域的代码会发生“resource contention”资源冲突(争夺资源)

3 FTP问题

  • servers
    服务器:载有文件的计算机
  • path
    路径:web目录

3.1 经理给员工分配任务

本项目将体会信号量的两个用途:

  • 1、竞争:作用域critical region用于保护全局资源
  • 2、同步:监控子线程完成动作(thread-to-thread communication 的一种)

任务描述

经理需要去FTP上下载一个文件夹(文件数组)的内容!

他找了n个员工,让每个员工从目标文件夹(文件数组)中下载1个文件!这n个员工同时下载!
完事之后,返回这n个员工总共下载的字节数 totalBytes

3.1.1 经理偷懒了

经理分配完任务后,就回家睡觉了!没有等待员工下载完成!结果返回的总字节数 totalBytes 很可能是0!!!

int DownloadSingleFile(const char *server,
						const char *path);
int DownloadAllFiles(const char *server,
					const char *files[],
					int n)
{
	int totalBytes = 0;
	Semaphore lock = 1;
	for(int i = 0; i < n; i++) {
		ThreadNew(___, DownloadHelper,
				server, files[i], 
				&totalBytes, 
				lock);
	}
// 这里有问题的,经理分配完任务之后,直接就返回totalBytes了,此时,可能员工还没下载完成!
	return totalBytes; 
}
// ThreadNew接收不到返回值,所以需要用函数入参的指针传出参数!
void DownloadHealper(const char *server,
					const char *path,
					int *pNumBytes,
					Semaphore lock)
{
	int bytesDownloaded = DownloadSingleFile(server, path);
	SemaphoreWait(lock); // critical region begin >>>
	(*pNumBytes) += bytesDownloaded;
	SemaphoreSignal(lock); // <<< critical region end
}

3.1.2 让经理等待员工下载完成

int DownloadAllFiles(const char *server,
					const char *files[],
					int n)
{
	int totalBytes = 0;
	Semaphore lock = 1;
	Semaphore childrenDone = 0; // 用于监控孩儿们下载完文件没有!!
	for(int i = 0; i < n; i++) {
		ThreadNew(___, DownloadHelper,
				server, files[i], 
				&totalBytes, 
				lock,
				childrenDone);
	}
// 这里有问题的,经理分配完任务之后,直接就返回totalBytes了,此时,可能员工还没下载完成!
// 把经理拉回来监控孩儿们!!!
	for(int i = 0; i < n; i++) {
	// -- n 次,共有n个孩儿干活,让每个孩儿完成工作后,做1次 ++ 操作
		SemaphoreWait(childrenDown); 
	}
	return totalBytes; 
}
// ThreadNew接收不到返回值,所以需要用函数入参的指针传出参数!
void DownloadHealper(const char *server,
					const char *path,
					int *pNumBytes,
					Semaphore lock,
					Semaphore parentToSignal)
{
	int bytesDownloaded = DownloadSingleFile(server, path);
	SemaphoreWait(lock); // critical region begin >>>
	(*pNumBytes) += bytesDownloaded;
	SemaphoreSignal(lock); // <<< critical region end
	SemaphoreSignal(parentToSignal); // 下载完成后给信号量做 ++操作
}

问题:在DownloadHealper()中,如果将SemaphoreWait(lock); 提前放在DownloadSingleFile()会怎么样?改动代码如下:

// ThreadNew接收不到返回值,所以需要用函数入参的指针传出参数!
void DownloadHealper(const char *server,
					const char *path,
					int *pNumBytes,
					Semaphore lock,
					Semaphore parentToSignal)
{
	// 向前扩大 critical region
	SemaphoreWait(lock); // critical region begin >>>
	int bytesDownloaded = DownloadSingleFile(server, path);
	(*pNumBytes) += bytesDownloaded;
	SemaphoreSignal(lock); // <<< critical region end
	SemaphoreSignal(parentToSignal); // 下载完成后给信号量做 ++操作
}


这样的话,孩儿们的并行下载变成了孩儿们逐个下载文件,并行下载失去了作用!会消耗大量时间!

3.1.3 避开全局资源争夺的方法

避免孩子们争夺资源的办法:就是提前给每个孩子均等分配资源,"1人1个" 就不抢了

将下载的总字节数 totalBytes 定义成 n 个元素的数组,为每个孩儿开辟一个存储空间,存放孩儿们自个下载的字节数,在经理那里对totalBytes数组中的元素加和,得到总字节数!

问题:如果孩儿太多,那么 downloadBytes[n] 这个数组肯定很大!太浪费空间了!

int DownloadAllFiles(const char *server,
					const char *files[],
					int n)
{
	int downloadBytes[n];
	int totalBytes = 0;
	Semaphore lock = 1;
	Semaphore childrenDone = 0; // 用于监控孩儿们下载完文件没有!!
	for(int i = 0; i < n; i++) {
		ThreadNew(___, DownloadHelper,
				server, files[i], 
				downloadBytes, 
				i,
				lock,
				childrenDone);
	}
// 这里有问题的,经理分配完任务之后,直接就返回downloadBytes了,此时,可能员工还没下载完成!
// 把经理拉回来监控孩儿们!!!
	for(int i = 0; i < n; i++) {
	// -- n 次,共有n个孩儿干活,让每个孩儿完成工作后,做1次 ++ 操作
		SemaphoreWait(childrenDown); 
	}
	// 由经理进行孩儿们的下载总字节数计算
	for(int i = 0; i < n; i++) {
		totalBytes += downloadBytes[i];
	}
	return totalBytes; 
}
// ThreadNew接收不到返回值,所以需要用函数入参的指针传出参数!
void DownloadHealper(const char *server,
					const char *path,
					int *aNumBytes,
					int myId,
					Semaphore lock,
					Semaphore parentToSignal)
{
	int bytesDownloaded = DownloadSingleFile(server, path);
	// SemaphoreWait(lock); // critical region begin >>>
	aNumBytes[myId] = bytesDownloaded; // 每个孩儿有自己独立的空间存放下载字节数
	// SemaphoreSignal(lock); // <<< critical region end
	SemaphoreSignal(parentToSignal); // 下载完成后给信号量做 ++操作
}

4 冰激凌商店模拟问题

思考问题的流程:

步骤关键词说明
1定义问题把问题描述清楚
2实现方案头脑风暴,将问题进一步细化,思考每一部分的解决方案
3具体实现
  • 经理(数量:1个)
    负责检查店员制作的冰激凌是否合格,经理办公室每次只允许1个店员进入,即:经理每次只能检查1个店员制作的冰激凌;
  • 店员(数量:10~40个)
    负责制作可口的冰激凌,每个店员同一时间只能制作1个冰激凌;
  • 顾客(数量:10个)
    去找店员订购冰激凌(1~4个限制),等拿到冰激凌后找收银员结账,然后离开商店;
  • 收银员(数量:1个)
    需要应对10个顾客,每次只能为1个顾客结账!要有“先来后到”哦,为先到的顾客先提供服务!

请添加图片描述

5 函数式编程Scheme

5.1 Scheme 概述

古老的几何学:丈量土地:对时间和空间进行形式化表述,归纳出一套讨论数学真理的形式化方法!
这直接造就了“公理化方法(axiomatic method)”和各种现代化数学的产生!

计算科学研究的:对“计算过程”形式化表述!

控制复杂度(complexity)的技术

  • 黑盒(black-box)抽象
    目的① 封装。将处理过程放进1个黑盒之中隐匿细节,从而去构建更大的黑盒!
    目的② 泛化。使得表达方式具有普遍性,可以应对多种不同的对象!
  • 约定接口(interface)
    整型加法、字符串加法、多项式加法、电信号加法虽然这些都是加法,但是实现是不一样的!如何增加“普遍性”,让加法对这些不同的对象都适用呢?这就要用到接口(回调函数)!
  • 元语言(metalinguistic)抽象

学习一门语言:

  • 基本元素:
    primitive data type 基本数据类型;
    operator 操作符;

  • 组合的方法:
    combination 组合式 = expression 表达式
    prefix notation 前缀表示法(操作符在操作数的左侧)

  • 抽象的方法

5.2 VSCode + ChezScheme开发环境搭建

5.2.1 下载并安装ChezScheme

ChezScheme下载网址:
https://cisco.github.io/ChezScheme/

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

5.2.2 环境变量配置

在这里插入图片描述

5.2.2.1 ChezScheme的命令路径:

64位机:
在这里插入图片描述
32位机:
在这里插入图片描述

5.2.2.2 添加ChezScheme命令路径到用户路径

在这里插入图片描述

5.2.2.3 验证ChezScheme是否安装成功

在这里插入图片描述

在这里插入图片描述

5.2.3 VSCode 配置

5.2.3.1 VSCode 安装 Scheme 语法高亮插件

在这里插入图片描述

5.2.3.2 VSCode 安装 Code Runner 插件

在这里插入图片描述

5.2.3.3 用 json 设置 VSCode

在这里插入图片描述

在这里插入图片描述

配置代码 settings.json

{
    "code-runner.runInTerminal": true,
    "code-runner.executorMapByFileExtension": {
    ".ss": "scheme"
    }
 }
出现了错误 csi !

scheme的命令行参数是 scheme,不是csi -script!
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

5.2.3.4 成功运行 scheme 程序

在这里插入图片描述

5.3 scheme 基本语法

基本数据类型 + 操作符 → 组合式

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

car 和 cdr

在这里插入图片描述

在这里插入图片描述

cons 合成新的列表

在这里插入图片描述
注意:Scheme或者任何Lisp语言的列表都是可以heterogeneous(异构的)。

append 拼接list

在这里插入图片描述

在这里插入图片描述

display 显示字串

在这里插入图片描述

5.4 scheme 抽象方法

5.4.1 定义变量

在这里插入图片描述

5.4.2 定义函数

在这里插入图片描述

在这里插入图片描述

5.4.3 递归

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值