mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-03-24 02:20:09 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
99cab85bd4
@ -1,34 +1,32 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10540-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 6 Screen01)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen01.html)
|
||||
[#]: author: (Alex Chadwick https://www.cl.cam.ac.uk)
|
||||
|
||||
计算机实验室 – 树莓派:课程 6 屏幕01
|
||||
计算机实验室之树莓派:课程 6 屏幕01
|
||||
======
|
||||
|
||||
欢迎来到屏幕系列课程。在本系列中,你将学习在树莓派中如何使用汇编代码控制屏幕,从显示随机数据开始,接着学习显示一个固定的图像和显示文本,然后格式化文本中的数字。假设你已经完成了 `OK` 系列课程的学习,所以在本系列中出现的有些知识将不再重复。
|
||||
欢迎来到屏幕系列课程。在本系列中,你将学习在树莓派中如何使用汇编代码控制屏幕,从显示随机数据开始,接着学习显示一个固定的图像和显示文本,然后格式化数字为文本。假设你已经完成了 OK 系列课程的学习,所以在本系列中出现的有些知识将不再重复。
|
||||
|
||||
第一节的屏幕课程教你一些关于图形的基础理论,然后用这些理论在屏幕或电视上显示一个图案。
|
||||
|
||||
### 1、入门
|
||||
|
||||
预期你已经完成了 `OK` 系列的课程,以及那个系列课程中在 `gpio.s` 和 `systemTimer.s` 文件中调用的函数。如果你没有完成这些,或你喜欢完美的实现,可以去下载 `OK05.s` 解决方案。在这里也要使用 `main.s` 文件中从开始到包含 `mov sp,#0x8000` 的这一行之前的代码。请删除这一行以后的部分。
|
||||
预期你已经完成了 OK 系列的课程,以及那个系列课程中在 `gpio.s` 和 `systemTimer.s` 文件中调用的函数。如果你没有完成这些,或你喜欢完美的实现,可以去下载 `OK05.s` 解决方案。在这里也要使用 `main.s` 文件中从开始到包含 `mov sp,#0x8000` 的这一行之前的代码。请删除这一行以后的部分。
|
||||
|
||||
### 2、计算机图形
|
||||
|
||||
将颜色表示为数字有几种方法。在这里我们专注于 RGB 方法,但 HSL 也是很常用的另一种方法。
|
||||
正如你所认识到的,从根本上来说,计算机是非常愚蠢的。它们只能执行有限数量的指令,仅仅能做一些数学,但是它们也能以某种方式来做很多很多的事情。而在这些事情中,我们目前想知道的是,计算机是如何将一个图像显示到屏幕上的。我们如何将这个问题转换成二进制?答案相当简单;我们为每个颜色设计一些编码方法,然后我们为在屏幕上的每个像素保存一个编码。一个像素就是你的屏幕上的一个非常小的点。如果你离屏幕足够近,你或许能够辨别出你的屏幕上的单个像素,能够看到每个图像都是由这些像素组成的。
|
||||
|
||||
正如你所认识到的,从根本上来说,计算机是非常愚蠢的。它们只能执行有限数量的指令,仅仅能做一些数学,但是它们也能以某种方式来做很多很多的事情。而在这些事情中,我们目前想知道的是,计算机是如何将一个图像显示到屏幕上的。我们如何将这个问题转换成二进制?答案相当简单;我们为每个颜色设计一些编码方法,然后我们为生个像素在屏幕上保存一个编码。一个像素在你的屏幕上就是一个非常小的点。如果你离屏幕足够近,你或许能够在你的屏幕上辨别出单个的像素,能够看到每个图像都是由这些像素组成的。
|
||||
> 将颜色表示为数字有几种方法。在这里我们专注于 RGB 方法,但 HSL 也是很常用的另一种方法。
|
||||
|
||||
随着计算机时代的到来,人们希望显示更多更复杂的图形,于是发明了图形卡的概念。图形卡是你的计算机上用来在屏幕上专门绘制图像的第二个处理器。它的任务就是将像素值信息转换成显示在屏幕上的亮度级别。在现代计算机中,图形卡已经能够做更多更复杂的事情了,比如绘制三维图形。但是在本系列教程中,我们只专注于图形卡的基本使用;从内存中取得像素然后把它显示到屏幕上。
|
||||
随着计算机时代的进步,人们希望显示越来越复杂的图形,于是发明了图形卡的概念。图形卡是你的计算机上用来在屏幕上专门绘制图像的第二个处理器。它的任务就是将像素值信息转换成显示在屏幕上的亮度级别。在现代计算机中,图形卡已经能够做更多更复杂的事情了,比如绘制三维图形。但是在本系列教程中,我们只专注于图形卡的基本使用;从内存中取得像素然后把它显示到屏幕上。
|
||||
|
||||
不念经使用哪种方法,现在马上出现的一个问题就是我们使用的颜色编码。这里有几种选择,每个产生不同的输出质量。为了完整起见,我在这里只是简单概述它们。
|
||||
|
||||
不过这里的一些图像几乎没有颜色,因为它们使用了一个叫空间抖动的技术。这允许它们以很少的颜色仍然能表示出非常好的图像。许多早期的操作系统就使用了这种技术。
|
||||
不管使用哪种方法,现在马上出现的一个问题就是我们使用的颜色编码。这里有几种选择,每个产生不同的输出质量。为了完整起见,我在这里只是简单概述它们。
|
||||
|
||||
| 名字 | 唯一颜色数量 | 描述 | 示例 |
|
||||
| ----------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------- |
|
||||
@ -40,27 +38,26 @@
|
||||
| 真彩色 | 16,777,216 | 每个像素使用 24 位去保存,前八位表示红色通道,第二个八位表示绿色通道,最后八位表示蓝色通道。 | ![True colour image of a bird][6] |
|
||||
| RGBA32 | 16,777,216 带 256 级透明度 | 每个像素使用 32 位去保存,前八位表示红色通道,第二个八位表示绿色通道,第三个八位表示蓝色通道。只有一个图像绘制在另一个图像的上方时才考虑使用透明通道,值为 0 时表示下面图像的颜色,值为 255 时表示上面这个图像的颜色,介于这两个值之间的所有值表示这两个图像颜色的混合。 ||
|
||||
|
||||
> 不过这里的一些图像只用了很少的颜色,因为它们使用了一个叫空间抖动的技术。这允许它们以很少的颜色仍然能表示出非常好的图像。许多早期的操作系统就使用了这种技术。
|
||||
|
||||
在本教程中,我们将从使用高色值开始。这样你就可以看到图像的构成,它的形成过程清楚,图像质量好,又不像真彩色那样占用太多的空间。也就是说,显示一个比较小的 800x600 像素的图像,它只需要小于 1 MiB 的空间。它另外的好处是它的大小是 2 次幂的倍数,相比真彩色这将极大地降低了获取信息的复杂度。
|
||||
|
||||
```
|
||||
保存帧缓冲给一台计算机带来了很大的内存负担。基于这种原因,早期计算机经常作弊,比如,保存一屏幕文本,在每次单独刷新时,它只绘制刷新了的字母。
|
||||
```
|
||||
|
||||
树莓派和它的图形处理器有一种特殊而奇怪的关系。在树莓派上,首先运行的事实上是图形处理器,它负责启动主处理器。这是很不常见的。最终它不会有太大的差别,但在许多交互中,它经常给人感觉主处理器是次要的,而图形处理器才是主要的。在树莓派上这两者之间依靠一个叫 “邮箱” 的东西来通讯。它们中的每一个都可以为对方投放邮件,这个邮件将在未来的某个时刻被对方收集并处理。我们将使用这个邮箱去向图形处理器请求一个地址。这个地址将是一个我们在屏幕上写入像素颜色信息的位置,我们称为帧缓冲,图形卡将定期检查这个位置,然后更新屏幕上相应的像素。
|
||||
|
||||
> 保存<ruby>帧缓冲<rt>frame buffer</rt></ruby>给计算机带来了很大的内存负担。基于这种原因,早期计算机经常作弊,比如,保存一屏幕文本,在每次单独刷新时,它只绘制刷新了的字母。
|
||||
|
||||
### 3、编写邮差程序
|
||||
|
||||
```
|
||||
消息传递是组件间通讯时使用的常见方法。一些操作系统在程序之间使用虚拟消息进行通讯。
|
||||
```
|
||||
接下来我们做的第一件事情就是编写一个“邮差”程序。它有两个方法:`MailboxRead`,从寄存器 `r0` 中的邮箱通道读取一个消息。而 `MailboxWrite`,将寄存器 `r0` 中的头 28 位的值写到寄存器 `r1` 中的邮箱通道。树莓派有 7 个与图形处理器进行通讯的邮箱通道。但仅第一个对我们有用,因为它用于协调帧缓冲。
|
||||
|
||||
接下来我们做的第一件事情就是编写一个“邮差”程序。它有两个方法:MailboxRead,从寄存器 `r0` 中的邮箱通道读取一个消息。而 MailboxWrite,将寄存器 `r0` 中的头 28 位的值写到寄存器 `r1` 中的邮箱通道。树莓派有 7 个与图形处理器进行通讯的邮箱通道。但仅第一个对我们有用,因为它用于协调帧缓冲。
|
||||
> 消息传递是组件间通讯时使用的常见方法。一些操作系统在程序之间使用虚拟消息进行通讯。
|
||||
|
||||
下列的表和示意图描述了邮箱的操作。
|
||||
|
||||
表 3.1 邮箱地址
|
||||
|
||||
| 地址 | 大小 / 字节 | 名字 | 描述 | 读 / 写 |
|
||||
| ---- | ---------- | ------------ | -------------------- | ------ |
|
||||
| 2000B880 | 4 | Read | 接收邮件 | R |
|
||||
| 2000B890 | 4 | Poll | 不检索接收 | R |
|
||||
| 2000B894 | 4 | Sender |发送者信息 | R |
|
||||
@ -70,20 +67,16 @@
|
||||
|
||||
为了给指定的邮箱发送一个消息:
|
||||
|
||||
1. 发送者等待,直到 `Status`字段的头一位为 0。
|
||||
1. 发送者等待,直到 `Status` 字段的头一位为 0。
|
||||
2. 发送者写入到 `Write`,低 4 位是要发送到的邮箱,高 28 位是要写入的消息。
|
||||
|
||||
|
||||
|
||||
为了读取一个消息:
|
||||
|
||||
1. 接收者等待,直到 `Status` 字段的第 30 位为 0。
|
||||
2. 接收者读取消息。
|
||||
3. 接收者确认消息来自正确的邮箱,否则再次重试。
|
||||
|
||||
|
||||
|
||||
如果你觉得有信心,你现在有足够的信息去写出我们所需的两个方法。如果没有信心,请继续往下看。
|
||||
如果你觉得有信心,你现在已经有足够的信息去写出我们所需的两个方法。如果没有信心,请继续往下看。
|
||||
|
||||
与以前一样,我建议你实现的第一个方法是获取邮箱区域的地址。
|
||||
|
||||
@ -103,12 +96,11 @@ mov pc,lr
|
||||
5. 将写入的值和邮箱通道组合到一起。
|
||||
6. 写入到 `Write`。
|
||||
|
||||
|
||||
|
||||
我们来按顺序写出它们中的每一步。
|
||||
|
||||
1.
|
||||
```assembly
|
||||
1. 这将实现我们验证 `r0` 和 `r1` 的目的。`tst` 是通过计算两个操作数的逻辑与来比较两个操作数的函数,然后将结果与 0 进行比较。在本案例中,它将检查在寄存器 `r0` 中的输入的低 4 位是否为全 0。
|
||||
|
||||
```assembly
|
||||
.globl MailboxWrite
|
||||
MailboxWrite:
|
||||
tst r0,#0b1111
|
||||
@ -117,14 +109,11 @@ cmp r1,#15
|
||||
movhi pc,lr
|
||||
```
|
||||
|
||||
```assembly
|
||||
tst reg,#val 计算寄存器 reg 和 #val 的逻辑与,然后将计算结果与 0 进行比较。
|
||||
```
|
||||
> `tst reg,#val` 计算寄存器 `reg` 和 `#val` 的逻辑与,然后将计算结果与 0 进行比较。
|
||||
|
||||
这将实现我们验证 `r0` 和 `r1` 的目的。`tst` 是通过计算两个操作数的逻辑与来比较两个操作数的函数,然后将结果与 0 进行比较。在本案例中,它将检查在寄存器 `r0` 中的输入的低 4 位是否为全 0。
|
||||
2. 这段代码确保我们不会覆盖我们的值,或链接寄存器,然后调用 `GetMailboxBase`。
|
||||
|
||||
2.
|
||||
```assembly
|
||||
```assembly
|
||||
channel .req r1
|
||||
value .req r2
|
||||
mov value,r0
|
||||
@ -133,48 +122,39 @@ bl GetMailboxBase
|
||||
mailbox .req r0
|
||||
```
|
||||
|
||||
这段代码确保我们不会覆盖我们的值,或链接寄存器,然后调用 `GetMailboxBase`。
|
||||
3. 这段代码加载当前状态。
|
||||
|
||||
3.
|
||||
```assembly
|
||||
```assembly
|
||||
wait1$:
|
||||
status .req r3
|
||||
ldr status,[mailbox,#0x18]
|
||||
```
|
||||
|
||||
这段代码加载当前状态。
|
||||
4. 这段代码检查状态字段的头一位是否为 0,如果不为 0,循环回到第 3 步。
|
||||
|
||||
4.
|
||||
```assembly
|
||||
```assembly
|
||||
tst status,#0x80000000
|
||||
.unreq status
|
||||
bne wait1$
|
||||
```
|
||||
|
||||
这段代码检查状态字段的头一位是否为 0,如果不为 0,循环回到第 3 步。
|
||||
5. 这段代码将通道和值组合到一起。
|
||||
|
||||
5.
|
||||
```assembly
|
||||
```assembly
|
||||
add value,channel
|
||||
.unreq channel
|
||||
```
|
||||
|
||||
这段代码将通道和值组合到一起。
|
||||
6. 这段代码保存结果到写入字段。
|
||||
|
||||
6.
|
||||
```assembly
|
||||
```assembly
|
||||
str value,[mailbox,#0x20]
|
||||
.unreq value
|
||||
.unreq mailbox
|
||||
pop {pc}
|
||||
```
|
||||
|
||||
这段代码保存结果到写入字段。
|
||||
|
||||
|
||||
|
||||
|
||||
MailboxRead 的代码和它非常类似。
|
||||
`MailboxRead` 的代码和它非常类似。
|
||||
|
||||
1. 我们的输入将从哪个邮箱读取(`r0`)。我们必须要验证邮箱的真实性。不要忘了验证输入。
|
||||
2. 使用 `GetMailboxBase` 去检索地址。
|
||||
@ -184,22 +164,20 @@ MailboxRead 的代码和它非常类似。
|
||||
6. 检查邮箱是否是我们所要的,如果不是返回到第 3 步。
|
||||
7. 返回结果。
|
||||
|
||||
|
||||
|
||||
我们来按顺序写出它们中的每一步。
|
||||
|
||||
1.
|
||||
```assembly
|
||||
1. 这一段代码来验证 `r0` 中的值。
|
||||
|
||||
```assembly
|
||||
.globl MailboxRead
|
||||
MailboxRead:
|
||||
cmp r0,#15
|
||||
movhi pc,lr
|
||||
```
|
||||
|
||||
这一段代码来验证 `r0` 中的值。
|
||||
2. 这段代码确保我们不会覆盖掉我们的值,或链接寄存器,然后调用 `GetMailboxBase`。
|
||||
|
||||
2.
|
||||
```assembly
|
||||
```assembly
|
||||
channel .req r1
|
||||
mov channel,r0
|
||||
push {lr}
|
||||
@ -207,37 +185,33 @@ bl GetMailboxBase
|
||||
mailbox .req r0
|
||||
```
|
||||
|
||||
这段代码确保我们不会覆盖掉我们的值,或链接寄存器,然后调用 `GetMailboxBase`。
|
||||
3. 这段代码加载当前状态。
|
||||
|
||||
3.
|
||||
```assembly
|
||||
```assembly
|
||||
rightmail$:
|
||||
wait2$:
|
||||
status .req r2
|
||||
ldr status,[mailbox,#0x18]
|
||||
```
|
||||
|
||||
这段代码加载当前状态。
|
||||
4. 这段代码检查状态字段第 30 位是否为 0,如果不为 0,返回到第 3 步。
|
||||
|
||||
4.
|
||||
```assembly
|
||||
```assembly
|
||||
tst status,#0x40000000
|
||||
.unreq status
|
||||
bne wait2$
|
||||
```
|
||||
|
||||
这段代码检查状态字段第 30 位是否为 0,如果不为 0,返回到第 3 步。
|
||||
5. 这段代码从邮箱中读取下一条消息。
|
||||
|
||||
5.
|
||||
```assembly
|
||||
```assembly
|
||||
mail .req r2
|
||||
ldr mail,[mailbox,#0]
|
||||
```
|
||||
|
||||
这段代码从邮箱中读取下一条消息。
|
||||
6. 这段代码检查我们正在读取的邮箱通道是否为提供给我们的通道。如果不是,返回到第 3 步。
|
||||
|
||||
6.
|
||||
```assembly
|
||||
```assembly
|
||||
inchan .req r3
|
||||
and inchan,mail,#0b1111
|
||||
teq inchan,channel
|
||||
@ -247,31 +221,22 @@ bne rightmail$
|
||||
.unreq channel
|
||||
```
|
||||
|
||||
这段代码检查我们正在读取的邮箱通道是否为提供给我们的通道。如果不是,返回到第 3 步。
|
||||
7. 这段代码将答案(邮件的前 28 位)移动到寄存器 `r0` 中。
|
||||
|
||||
7.
|
||||
|
||||
```assembly
|
||||
```assembly
|
||||
and r0,mail,#0xfffffff0
|
||||
.unreq mail
|
||||
pop {pc}
|
||||
```
|
||||
|
||||
这段代码将答案(邮件的前 28 位)移动到寄存器 `r0` 中。
|
||||
|
||||
|
||||
|
||||
|
||||
### 4、我心爱的图形处理器
|
||||
|
||||
通过我们新的邮差程序,我们现在已经能够向图形卡上发送消息了。我们应该发送些什么呢?这对我来说可能是个很难找到答案的问题,因为它不是任何线上手册能够找到答案的问题。尽管如此,通过查找有关树莓派的 GNU/Linux,我们能够找出我们需要发送的内容。
|
||||
|
||||
```
|
||||
由于在树莓派的内存是在图形处理器和主处理器之间共享的,我们能够只发送可以找到我们信息的位置即可。这就是 DMA,许多复杂的设备使用这种技术去加速访问时间。
|
||||
```
|
||||
|
||||
消息很简单。我们描述我们想要的帧缓冲区,而图形卡要么接受我们的请求,给我们返回一个 0,然后用我们写的一个小的调查问卷来填充屏幕;要么发送一个非 0 值,我们知道那表示很遗憾(出错了)。不幸的是,我并不知道它返回的其它数字是什么,也不知道它意味着什么,但我们知道仅当它返回一个 0,才表示一切顺利。幸运的是,对于合理的输入,它总是返回一个 0,因此我们不用过于担心。
|
||||
|
||||
> 由于在树莓派的内存是在图形处理器和主处理器之间共享的,我们能够只发送可以找到我们信息的位置即可。这就是 DMA,许多复杂的设备使用这种技术去加速访问时间。
|
||||
|
||||
为简单起见,我们将提前设计好我们的请求,并将它保存到 `framebuffer.s` 文件的 `.data` 节中,它的代码如下:
|
||||
|
||||
```assembly
|
||||
@ -293,11 +258,9 @@ FrameBufferInfo:
|
||||
|
||||
这就是我们发送到图形处理器的消息格式。第一对两个关键字描述了物理宽度和高度。第二对关键字描述了虚拟宽度和高度。帧缓冲的宽度和高度就是虚拟的宽度和高度,而 GPU 按需要伸缩帧缓冲去填充物理屏幕。如果 GPU 接受我们的请求,接下来的关键字将是 GPU 去填充的参数。它们是帧缓冲每行的字节数,在本案例中它是 `2 × 1024 = 2048`。下一个关键字是每个像素分配的位数。使用了一个 16 作为值意味着图形处理器使用了我们上面所描述的高色值模式。值为 24 是真彩色,而值为 32 则是 RGBA32。接下来的两个关键字是 x 和 y 偏移量,它表示当将帧缓冲复制到屏幕时,从屏幕左上角跳过的像素数目。最后两个关键字是由图形处理器填写的,第一个表示指向帧缓冲的实际指针,第二个是用字节数表示的帧缓冲大小。
|
||||
|
||||
```
|
||||
当设备使用 DMA 时,对齐约束变得非常重要。GPU 预期消息都是 16 字节对齐的。
|
||||
```
|
||||
在这里我非常谨慎地使用了一个 `.align 4` 指令。正如前面所讨论的,这样确保了下一行地址的低 4 位是 0。所以,我们可以确保将被放到那个地址上的帧缓冲(`FrameBufferInfo`)是可以发送到图形处理器上的,因为我们的邮箱仅发送低 4 位全为 0 的值。
|
||||
|
||||
在这里我非常谨慎地使用了一个 `.align 4` 指令。正如前面所讨论的,这样确保了下一行地址的低 4 位是 0。所以,我们可以确保将被放到那个地址上的帧缓冲是可以发送到图形处理器上的,因为我们的邮箱仅发送低 4 位全为 0 的值。
|
||||
> 当设备使用 DMA 时,对齐约束变得非常重要。GPU 预期该消息都是 16 字节对齐的。
|
||||
|
||||
到目前为止,我们已经有了待发送的消息,我们可以写代码去发送它了。通讯将按如下的步骤进行:
|
||||
|
||||
@ -305,8 +268,6 @@ FrameBufferInfo:
|
||||
2. 从邮箱 1 上读取结果。如果它是非 0 值,意味着我们没有请求一个正确的帧缓冲。
|
||||
3. 复制我们的图像到指针,这时图像将出现在屏幕上!
|
||||
|
||||
|
||||
|
||||
我在步骤 1 中说了一些以前没有提到的事情。我们在发送之前,在帧缓冲地址上加了 `0x40000000`。这其实是一个给 GPU 的特殊信号,它告诉 GPU 应该如何写到结构上。如果我们只是发送地址,GPU 将写到它的回复上,这样不能保证我们可以通过刷新缓存看到它。缓存是处理器使用的值在它们被发送到存储之前保存在内存中的片段。通过加上 `0x40000000`,我们告诉 GPU 不要将写入到它的缓存中,这样将确保我们能够看到变化。
|
||||
|
||||
因为在那里发生很多事情,因此最好将它实现为一个函数,而不是将它以代码的方式写入到 `main.s` 中。我们将要写一个函数 `InitialiseFrameBuffer`,由它来完成所有协调和返回指向到上面提到的帧缓冲数据的指针。为方便起见,我们还将帧缓冲的宽度、高度、位深作为这个方法的输入,这样就很容易地修改 `main.s` 而不必知道协调的细节了。
|
||||
@ -320,12 +281,11 @@ FrameBufferInfo:
|
||||
5. 如果回复是非 0 值,方法失败。我们应该返回 0 去表示失败。
|
||||
6. 返回指向帧缓冲信息的指针。
|
||||
|
||||
|
||||
|
||||
现在,我们开始写更多的方法。以下是上面其中一个实现。
|
||||
|
||||
1.
|
||||
```assembly
|
||||
1. 这段代码检查宽度和高度是小于或等于 4096,位深小于或等于 32。这里再次使用了条件运行的技巧。相信自己这是可行的。
|
||||
|
||||
```assembly
|
||||
.section .text
|
||||
.globl InitialiseFrameBuffer
|
||||
InitialiseFrameBuffer:
|
||||
@ -340,10 +300,9 @@ movhi result,#0
|
||||
movhi pc,lr
|
||||
```
|
||||
|
||||
这段代码检查宽度和高度是小于或等于 4096,位深小于或等于 32。这里再次使用了条件运行的技巧。相信自己这是可行的。
|
||||
2. 这段代码写入到我们上面定义的帧缓冲结构中。我也趁机将链接寄存器推入到栈上。
|
||||
|
||||
2.
|
||||
```assembly
|
||||
```assembly
|
||||
fbInfoAddr .req r3
|
||||
push {lr}
|
||||
ldr fbInfoAddr,=FrameBufferInfo
|
||||
@ -357,53 +316,44 @@ str bitDepth,[fbInfoAddr,#20]
|
||||
.unreq bitDepth
|
||||
```
|
||||
|
||||
这段代码写入到我们上面定义的帧缓冲结构中。我也趁机将链接寄存器推入到栈上。
|
||||
3. `MailboxWrite` 方法的输入是写入到寄存器 `r0` 中的值,并将通道写入到寄存器 `r1` 中。
|
||||
|
||||
3.
|
||||
```assembly
|
||||
```assembly
|
||||
mov r0,fbInfoAddr
|
||||
add r0,#0x40000000
|
||||
mov r1,#1
|
||||
bl MailboxWrite
|
||||
```
|
||||
|
||||
`MailboxWrite` 方法的输入是写入到寄存器 `r0` 中的值,并将通道写入到寄存器 `r1` 中。
|
||||
4. `MailboxRead` 方法的输入是写入到寄存器 `r0` 中的通道,而输出是值读数。
|
||||
|
||||
4.
|
||||
```assembly
|
||||
```assembly
|
||||
mov r0,#1
|
||||
bl MailboxRead
|
||||
```
|
||||
|
||||
`MailboxRead` 方法的输入是写入到寄存器 `r0` 中的通道,而输出是值读数。
|
||||
5. 这段代码检查 `MailboxRead` 方法的结果是否为 0,如果不为 0,则返回 0。
|
||||
|
||||
5.
|
||||
```assembly
|
||||
```assembly
|
||||
teq result,#0
|
||||
movne result,#0
|
||||
popne {pc}
|
||||
```
|
||||
|
||||
这段代码检查 `MailboxRead` 方法的结果是否为 0,如果不为 0,则返回 0。
|
||||
6. 这是代码结束,并返回帧缓冲信息地址。
|
||||
|
||||
6.
|
||||
```assembly
|
||||
```assembly
|
||||
mov result,fbInfoAddr
|
||||
pop {pc}
|
||||
.unreq result
|
||||
.unreq fbInfoAddr
|
||||
```
|
||||
|
||||
这是代码结束,并返回帧缓冲信息地址。
|
||||
|
||||
|
||||
|
||||
|
||||
### 5、在一帧中一行之内的一个像素
|
||||
|
||||
到目前为止,我们已经创建了与图形处理器通讯的方法。现在它已经能够给我们返回一个指向到帧缓冲的指针去绘制图形了。我们现在来绘制一个图形。
|
||||
|
||||
第一示例,我们将在屏幕上绘制连续的颜色。它看起来并不漂亮,但至少能说明它在工作。我们如何才能在帧缓冲中设置每个像素为一个连续的数字,并且要持续不断地这样做。
|
||||
第一示例中,我们将在屏幕上绘制连续的颜色。它看起来并不漂亮,但至少能说明它在工作。我们如何才能在帧缓冲中设置每个像素为一个连续的数字,并且要持续不断地这样做。
|
||||
|
||||
将下列代码复制到 `main.s` 文件中,并放置在 `mov sp,#0x8000` 行之后。
|
||||
|
||||
@ -414,7 +364,7 @@ mov r2,#16
|
||||
bl InitialiseFrameBuffer
|
||||
```
|
||||
|
||||
这段代码使用了我们的 `InitialiseFrameBuffer` 方法,简单地创建了一个宽 1024、高 768、位深为 16 的帧缓冲区。在这里,如果你愿意可以尝试使用不同的值,只要整个代码中都一样就可以。如果图形处理器没有给我们创建好一个帧缓冲区,这个方法将返回 0,我们最好检查一下返回值,如果出现返回值为 0 的情况,我们打开 `OK` LED 灯。
|
||||
这段代码使用了我们的 `InitialiseFrameBuffer` 方法,简单地创建了一个宽 1024、高 768、位深为 16 的帧缓冲区。在这里,如果你愿意可以尝试使用不同的值,只要整个代码中都一样就可以。如果图形处理器没有给我们创建好一个帧缓冲区,这个方法将返回 0,我们最好检查一下返回值,如果出现返回值为 0 的情况,我们打开 OK LED 灯。
|
||||
|
||||
```assembly
|
||||
teq r0,#0
|
||||
@ -435,8 +385,7 @@ fbInfoAddr .req r4
|
||||
mov fbInfoAddr,r0
|
||||
```
|
||||
|
||||
现在,我们已经有了帧缓冲信息的地址,我们需要取得帧缓冲信息的指针,并开始绘制屏幕。我们使用两个循环来做实现,一个走行,一个走列。事实上,树莓派中的大多数应用程序中,图片都是以从左右然后从上下到的顺序来保存的,因此我们也按这个顺序来写循环。
|
||||
|
||||
现在,我们已经有了帧缓冲信息的地址,我们需要取得帧缓冲信息的指针,并开始绘制屏幕。我们使用两个循环来做实现,一个走行,一个走列。事实上,树莓派中的大多数应用程序中,图片都是以从左到右然后从上到下的顺序来保存的,因此我们也按这个顺序来写循环。
|
||||
|
||||
```assembly
|
||||
render$:
|
||||
@ -470,9 +419,7 @@ render$:
|
||||
.unreq fbInfoAddr
|
||||
```
|
||||
|
||||
```assembly
|
||||
strh reg,[dest] 将寄存器中的低位半个字保存到给定的 dest 地址上。
|
||||
```
|
||||
> `strh reg,[dest]` 将寄存器中的低位半个字保存到给定的 `dest` 地址上。
|
||||
|
||||
这是一个很长的代码块,它嵌套了三层循环。为了帮你理清头绪,我们将循环进行缩进处理,这就有点类似于高级编程语言,而汇编器会忽略掉这些用于缩进的 `tab` 字符。我们看到,在这里它从帧缓冲信息结构中加载了帧缓冲的地址,然后基于每行来循环,接着是每行上的每个像素。在每个像素上,我们使用一个 `strh`(保存半个字)命令去保存当前颜色,然后增加地址继续写入。每行绘制完成后,我们增加绘制的颜色号。在整个屏幕绘制完成后,我们跳转到开始位置。
|
||||
|
||||
@ -489,7 +436,7 @@ via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen01.html
|
||||
作者:[Alex Chadwick][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,94 @@
|
||||
Pony 编程语言简介
|
||||
======
|
||||
|
||||
> Pony,一种“Rust 遇上 Erlang”的语言,让开发快捷、安全、高效、高并发的程序更简单。
|
||||
|
||||

|
||||
|
||||
在 [Wallaroo Labs][1],我是工程副总裁,我们正在构建一个用 [Pony][3] 编程语言编写的 [高性能分布式流处理器][2]。大多数人没有听说过 Pony,但它一直是 Wallaroo 的最佳选择,它也可能成为你的下一个项目的最佳选择。
|
||||
|
||||
> “一门编程语言只是另一种工具。与语法无关,与表达性无关,与范式或模型无关,仅与解决难题有关。” —Sylvan Clebsch,Pony 的创建者
|
||||
|
||||
我是 Pony 项目的贡献者,但在这里我要谈谈为什么 Pony 对于像 Wallaroo 这样的应用是个好选择,并分享我使用 Pony 的方式。如果你对我们为什么使用 Pony 来编写 Wallaroo 甚感兴趣,我们有一篇关于它的 [博文][4]。
|
||||
|
||||
### Pony 是什么?
|
||||
|
||||
你可以把 Pony 想象成某种“Rust 遇上 Erlang”的东西。Pony 有着最引人注目的特性,它们是:
|
||||
|
||||
* 类型安全
|
||||
* 存储安全
|
||||
* 异常安全
|
||||
* 无数据竞争
|
||||
* 无死锁
|
||||
|
||||
此外,它可以被编译为高效的本地代码,它是在开放的情况下开发的,在两句版 BSD 许可证下发布。
|
||||
|
||||
以上说的功能不少,但在这里我将重点关注那些对我们公司来说采用 Pony 至关重要的功能。
|
||||
|
||||
### 为什么使用 Pony?
|
||||
|
||||
使用大多数我们现有的工具编写快速、安全、高效、高并发的程序并非易事。“快速、高效、高并发”是可实现的目标,但加入“安全”之后,就困难了许多。对于 Wallaroo,我们希望同时实现四个目标,而 Pony 让实现它们更加简单。
|
||||
|
||||
#### 高并发
|
||||
|
||||
Pony 让并发变得简单。部分是通过提供一个固执的并发方式实现的。在 Pony 语言中,所有的并发都是通过 [Actor 模型][5] 进行的。
|
||||
|
||||
Actor 模型以在 Erlang 和 Akka 中的实现最为著名。Actor 模型出现于上世纪 70 年代,细节因实现方式而异。不变的是,所有计算都由通过异步消息进行通信的 actor 来执行。
|
||||
|
||||
你可以用这种方式来看待 Actor 模型:面向对象中的对象是状态 + 同步方法,而 actor 是状态 + 异步方法。
|
||||
|
||||
当一个 actor 收到一个消息时,它执行相应的方法。该方法可以在只有该 actor 可访问的状态下运行。Actor 模型允许我们以并发安全的方式使用可变状态。每个 actor 都是单线程的。一个 actor 中的两个方法绝不会并发运行。这意味着,在给定的 actor 中,数据更新不会引起数据竞争或通常与线程和可变状态相关的其他问题。
|
||||
|
||||
#### 快速高效
|
||||
|
||||
Pony actor 通过一个高效的工作窃取调度程序来调度。每个可用的 CPU 都有一个单独 Pony 调度程序。这种每个核心一个线程的并发模型是 Pony 尝试与 CPU 协同工作以尽可能高效运行的一部分。Pony 运行时尝试尽可能利用 CPU 缓存。代码越少干扰缓存,运行得越好。Pony 意在帮你的代码与 CPU 缓存友好相处。
|
||||
|
||||
Pony 的运行时还会有每个 actor 的堆,因此在垃圾收集期间,没有 “停止一切” 的垃圾收集步骤。这意味着你的程序总是至少能做一点工作。因此 Pony 程序最终具有非常一致的性能和可预测的延迟。
|
||||
|
||||
#### 安全
|
||||
|
||||
Pony 类型系统引入了一个新概念:引用能力,它使得数据安全成为类型系统的一部分。Pony 语言中每种变量的类型都包含了有关如何在 actor 之间分享数据的信息。Pony 编译器用这些信息来确认,在编译时,你的代码是无数据竞争和无死锁的。
|
||||
|
||||
如果这听起来有点像 Rust,那是因为本来就是这样的。Pony 的引用功能和 Rust 的借用检查器都提供数据安全性;它们只是以不同的方式来接近这个目标,并有不同的权衡。
|
||||
|
||||
### Pony 适合你吗?
|
||||
|
||||
决定是否要在一个非业余爱好的项目上使用一门新的编程语言是困难的。与其他方法想比,你必须权衡工具的适当性和不成熟度。那么,Pony 和你搭不搭呢?
|
||||
|
||||
如果你有一个困难的并发问题需要解决,那么 Pony 可能是一个好选择。解决并发应用问题是 Pony 之所以存在的理由。如果你能用一个单线程的 Python 脚本就完成所需操作,那你大概不需要它。如果你有一个困难的并发问题,你应该考虑 Pony 及其强大的无数据竞争、并发感知类型系统。
|
||||
|
||||
你将获得一个这样的编译器,它将阻止你引入许多与并发相关的错误,并在运行时为你提供出色的性能特征。
|
||||
|
||||
### 开始使用 Pony
|
||||
|
||||
如果你准备好开始使用 Pony,你需要先在 Pony 的网站上访问 [学习部分][6]。在这里你会找到安装 Pony 编译器的步骤和学习这门语言的资源。
|
||||
|
||||
如果你愿意为你正在使用的这个语言做出贡献,我们会在 GitHub 上为你提供一些 [初学者友好的问题][7]。
|
||||
|
||||
同时,我迫不及待地想在 [我们的 IRC 频道][8] 和 [Pony 邮件列表][9] 上与你交谈。
|
||||
|
||||
要了解更多有关 Pony 的消息,请参阅 Sean Allen 2018 年 7 月 16 日至 19 日在俄勒冈州波特兰举行的 [第 20 届 OSCON 会议][11] 上的演讲: [Pony,我如何学会停止担心并拥抱未经证实的技术][10]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/5/pony
|
||||
|
||||
作者:[Sean T Allen][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[beamrolling](https://github.com/beamrolling)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/seantallen
|
||||
[1]:http://www.wallaroolabs.com/
|
||||
[2]:https://github.com/wallaroolabs/wallaroo
|
||||
[3]:https://www.ponylang.org/
|
||||
[4]:https://blog.wallaroolabs.com/2017/10/why-we-used-pony-to-write-wallaroo/
|
||||
[5]:https://en.wikipedia.org/wiki/Actor_model
|
||||
[6]:https://www.ponylang.org/learn/
|
||||
[7]:https://github.com/ponylang/ponyc/issues?q=is%3Aissue+is%3Aopen+label%3A%22complexity%3A+beginner+friendly%22
|
||||
[8]:https://webchat.freenode.net/?channels=%23ponylang
|
||||
[9]:https://pony.groups.io/g/user
|
||||
[10]:https://conferences.oreilly.com/oscon/oscon-or/public/schedule/speaker/213590
|
||||
[11]:https://conferences.oreilly.com/oscon/oscon-or
|
@ -1,24 +1,27 @@
|
||||
如何从 Linux 上连接到远程桌面
|
||||
======
|
||||
|
||||
> Remmina 的极简用户界面使得远程访问 Linux / Windows 10 变得轻松。
|
||||
|
||||

|
||||
|
||||
根据维基百科,[远程桌面][1] 是一种“可以让个人电脑上的桌面环境在一个系统(通常是电脑,但是也可以是服务器)上远程运行并在另一个分开的客户端设备显示的软件或者操作系统特性”。
|
||||
根据维基百科,[远程桌面][1] 是一种“软件或者操作系统特性,它可以让个人电脑上的桌面环境在一个系统(通常是电脑,但是也可以是服务器)上远程运行,但在另一个分开的客户端设备显示”。
|
||||
|
||||
换句话说,远程桌面是用来访问在另一台电脑上运行的环境的。比如说 [ManageIQ/Integration tests][2] 仓库的拉取请求 (PR) 测试系统暴露了一个虚拟网络计算 (VNC) 连接端口,使得我能够远程浏览正被实时测试的拉取请求。远程桌面也被用于帮助客户解决电脑问题:在客户的许可下,你可以远程建立 VNC 或者远程桌面协议(RDP)连接来看或者交互式地访问电脑以寻找并解决问题。
|
||||
换句话说,远程桌面是用来访问在另一台电脑上运行的环境的。比如说 [ManageIQ/Integration tests][2] 仓库的拉取请求 (PR) 测试系统开放了一个虚拟网络计算 (VNC) 连接端口,使得我能够远程浏览正被实时测试的拉取请求。远程桌面也被用于帮助客户解决电脑问题:在客户的许可下,你可以远程建立 VNC 或者远程桌面协议(RDP)连接来查看或者交互式地访问该电脑以寻找并解决问题。
|
||||
|
||||
运用远程桌面连接软件可以建立这些连接。可供选择的软件有很多,我用 [Remmina][3] 因为我喜欢它极简、好用的用户界面 (UI)。它是用 GTK+ 编写的,在 GNU GPL 证书下它是开源的。
|
||||
运用远程桌面连接软件可以建立这些连接。可供选择的软件有很多,我用 [Remmina][3],因为我喜欢它极简、好用的用户界面 (UI)。它是用 GTK+ 编写的,在 GNU GPL 许可证开源。
|
||||
|
||||
在这篇文章里,我会解释如何使用 Remmina 客户端从一台 Linux 电脑上远程连接到 Windows 10 系统 和 Red Hat 企业版 Linux 7 系统。
|
||||
|
||||
### 在 Linux 上安装 Remmina
|
||||
|
||||
首先,你需要在你用来远程访问其它电脑的的主机上安装 Remmina。如果你用的是 Fedora,你可以运行如下的命令来安装 Remmina:
|
||||
|
||||
```
|
||||
sudo dnf install -y remmina
|
||||
```
|
||||
|
||||
如果你想在一个不同的 Linux 平台上安装 Remmina,跟着 [安装教程][4] 走。然后你会发现 Remmina 正和你其它软件待在一起(Remmina 在这张图片里被选中)。
|
||||
如果你想在一个不同的 Linux 平台上安装 Remmina,跟着 [安装教程][4] 走。然后你会发现 Remmina 正和你其它软件出现在一起(在这张图片里选中了 Remmina)。
|
||||
|
||||

|
||||
|
||||
@ -26,31 +29,31 @@ sudo dnf install -y remmina
|
||||
|
||||

|
||||
|
||||
Remmina 提供不同种类的连接,其中包括用来连接到 Windows 系统的 RDP 和 用来连接到 Linux 系统的 VNC。如你在上图左上角所见的,Remmina 的默认设置是 RDP。
|
||||
Remmina 提供不同种类的连接,其中包括用来连接到 Windows 系统的 RDP 和用来连接到 Linux 系统的 VNC。如你在上图左上角所见的,Remmina 的默认设置是 RDP。
|
||||
|
||||
### 连接到 Windows 10
|
||||
|
||||
在你通过 RDP 连接到一台 Windows 10 电脑之前,你必须修改权限以允许分享远程桌面并通过防火墙建立连接。
|
||||
|
||||
[注意: Windows 10 家庭版没有列出 RDP 特性][5]
|
||||
- [注意: Windows 10 家庭版没有列入 RDP 特性][5]
|
||||
|
||||
要许可远程桌面分享,在**文件管理器**界面右击**我的电脑 → 属性 → 远程设置**,接着在跳出的窗口中,勾选**在这台电脑上允许远程连接**,再点击**应用**。
|
||||
要许可远程桌面分享,在“文件管理器”界面右击“我的电脑 → 属性 → 远程设置”,接着在跳出的窗口中,勾选“在这台电脑上允许远程连接”,再点击“应用”。
|
||||
|
||||

|
||||
|
||||
然后,允许远程连接通过你的防火墙。首先在**开始菜单中**查找**防火墙设置**,选择**允许应用通过防火墙**。
|
||||
然后,允许远程连接通过你的防火墙。首先在“开始菜单”中查找“防火墙设置”,选择“允许应用通过防火墙”。
|
||||
|
||||

|
||||
|
||||
在打开的窗口中,在**允许的应用和特性**下找到**远程桌面**。根据你用来访问这个桌面的网络酌情勾选**隐私**和/或**公开**列的选框。点击**确定**。
|
||||
在打开的窗口中,在“允许的应用和特性”下找到“远程桌面”。根据你用来访问这个桌面的网络酌情勾选“隐私”和/或“公开”列的选框。点击“确定”。
|
||||
|
||||

|
||||
|
||||
回到你用来远程访问 Windows 主机的 Linux 电脑,打开 Remmina。输入你的 Windows 主机的 IP 地址,敲击回车键。(我怎么在 [Linux][6] 和 [Windws][7] 中定位我的 IP 地址?)看到提示后,输入你的用户名和密码,点击确定。
|
||||
回到你用来远程访问 Windows 主机的 Linux 电脑,打开 Remmina。输入你的 Windows 主机的 IP 地址,敲击回车键。(我怎么在 [Linux][6] 和 [Windws][7] 中确定我的 IP 地址?)看到提示后,输入你的用户名和密码,点击“确定”。
|
||||
|
||||

|
||||
|
||||
如果你被询问是否接受证书,点击确定。
|
||||
如果你被询问是否接受证书,点击“确定”。
|
||||
|
||||

|
||||
|
||||
@ -60,7 +63,7 @@ Remmina 提供不同种类的连接,其中包括用来连接到 Windows 系统
|
||||
|
||||
### 连接到 Red Hat 企业版 Linux 7
|
||||
|
||||
要在你的 RHEL7 电脑上允许远程访问,在 Linux 桌面上打开**所有设置**。
|
||||
要在你的 RHEL7 电脑上允许远程访问,在 Linux 桌面上打开“所有设置”。
|
||||
|
||||

|
||||
|
||||
@ -68,27 +71,27 @@ Remmina 提供不同种类的连接,其中包括用来连接到 Windows 系统
|
||||
|
||||

|
||||
|
||||
如果**屏幕分享**处于关闭状态,点击一下。一个窗口会弹出,你可以滑动到**打开**的位置。如果你想允许远程控制桌面,将**允许远程控制**调到**打开**。你同样也可以在两种访问选项间选择:一个能够让电脑的主要用户接受或者否绝连接要求,另一个能用密码验证连接。在窗口底部,选择被允许连接的网络界面,最后关闭窗口。
|
||||
如果“屏幕分享”处于关闭状态,点击一下。一个窗口会弹出,你可以滑动到“打开”的位置。如果你想允许远程控制桌面,将“允许远程控制”调到“打开”。你同样也可以在两种访问选项间选择:一个能够让电脑的主要用户接受或者否绝连接要求,另一个能用密码验证连接。在窗口底部,选择被允许连接的网络界面,最后关闭窗口。
|
||||
|
||||
接着,从**应用菜单 → 其它 → 防火墙**打开**防火墙设置**。
|
||||
接着,从“应用菜单 → 其它 → 防火墙”打开“防火墙设置”。
|
||||
|
||||

|
||||
|
||||
勾选 vnc-服务器旁边的选框(如下图所示)关闭窗口。接着直接到你远程电脑上的 Remmina,输入 你想连接到的 Linux 桌面的 IP 地址,选择 **VNC** 作为协议,点击**回车**键。
|
||||
勾选 “vnc-server”旁边的选框(如下图所示)关闭窗口。接着直接到你远程电脑上的 Remmina,输入你想连接到的 Linux 桌面的 IP 地址,选择 VNC 作为协议,点击回车键。
|
||||
|
||||

|
||||
|
||||
如果你之前选择的验证选项是**新连接必须询问访问许可**,RHEL 系统用户会看到这样的一个弹窗
|
||||
如果你之前选择的验证选项是“新连接必须询问访问许可”,RHEL 系统用户会看到这样的一个弹窗:
|
||||
|
||||

|
||||
|
||||
点击**接受**以成功进行远程连接。
|
||||
点击“接受”以成功进行远程连接。
|
||||
|
||||
如果你选择用密码验证连接,Remmina 会向你询问密码。
|
||||
|
||||

|
||||
|
||||
输入密码然后**确认**,你应该能连接到远程电脑。
|
||||
输入密码然后“确认”,你应该能连接到远程电脑。
|
||||
|
||||

|
||||
|
||||
@ -96,9 +99,9 @@ Remmina 提供不同种类的连接,其中包括用来连接到 Windows 系统
|
||||
|
||||
Remmina 提供如上图所示的标签化的 UI,就好像一个浏览器一样。在上图所示的左上角你可以看到两个标签:一个是之前建立的 WIndows 10 连接,另一个新的是 RHEL 连接。
|
||||
|
||||
在窗口的左侧,有一个有着**缩放窗口**,**全屏模式**,**偏好**,**截屏**,**断开连接**等选项的工具栏。你可以自己探索看那种适合你。
|
||||
在窗口的左侧,有一个有着“缩放窗口”、“全屏模式”、“偏好”、“截屏”、“断开连接”等选项的工具栏。你可以自己探索看那种适合你。
|
||||
|
||||
你也可以通过点击左上角的**+**号创建保存过的连接。根据你的连接情况填好表单点击**保存**。以下是一个 Windows 10 RDP 连接的示例:
|
||||
你也可以通过点击左上角的“+”号创建保存过的连接。根据你的连接情况填好表单点击“保存”。以下是一个 Windows 10 RDP 连接的示例:
|
||||
|
||||

|
||||
|
||||
@ -106,11 +109,11 @@ Remmina 提供如上图所示的标签化的 UI,就好像一个浏览器一样
|
||||
|
||||

|
||||
|
||||
点击一下它你不用补充细节就可以建立连接了。
|
||||
点击一下它,你不用补充细节就可以建立连接了。
|
||||
|
||||
### 补充说明
|
||||
|
||||
当你使用远程桌面软件时,你所有的操作都在远程桌面上消耗资源—— Remmina(或者其它类似软件)仅仅是一种与远程桌面交互的方式。你也可以通过 SSH 远程访问一台电脑,但那将会让你在那台电脑上局限于仅能使用文字的终端。
|
||||
当你使用远程桌面软件时,你所有的操作都在远程桌面上消耗资源 —— Remmina(或者其它类似软件)仅仅是一种与远程桌面交互的方式。你也可以通过 SSH 远程访问一台电脑,但那将会让你在那台电脑上局限于仅能使用文字的终端。
|
||||
|
||||
你也应当注意到当你允许你的电脑远程连接时,如果一名攻击者用这种方法获得你电脑的访问权同样会给你带来严重损失。因此当你不频繁使用远程桌面时,禁止远程桌面连接以及其在防火墙中相关的服务是很明智的做法。
|
||||
|
||||
@ -121,7 +124,7 @@ via: https://opensource.com/article/18/6/linux-remote-desktop
|
||||
作者:[Kedar Vijay Kulkarni][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[tomjlw](https://github.com/tomjlw)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,96 +0,0 @@
|
||||
Pony 编程语言简介
|
||||
======
|
||||
|
||||
Pony,一种“Rust 遇上 Erlang”的语言,让开发快捷,安全,高效,以及高并发程序更简单。
|
||||
|
||||

|
||||
|
||||
在 [Wallaroo Labs][1],我是副总工程师,我们正在构建一个用 [Pony][3] 编程语言编写的 [高性能分布式流处理器][2]。大多数人没有听说过 Pony,但它一直是 Wallaroo 的最佳选择,它也可能成为你的下一个项目的最佳选择。
|
||||
|
||||
> "一门编程语言只是另一种工具。与语法无关。与表达性无关。与范式或模型无关。仅与管理难题有关" —Sylvan Clebsch,Pony 的创建者
|
||||
|
||||
我是 Pony 项目的贡献者,但在这里我要谈谈为什么 Pony 对于像 Wallaroo 这样的应用是个好选择,并分享我使用 Pony 的方式。如果你对我们为什么使用 Pony 来编写 Wallaroo 甚感兴趣,我们有一篇关于它的 [博文][4]。
|
||||
|
||||
### Pony 是什么?
|
||||
|
||||
你可以把 Pony 想象成某种“Rust 遇上 Erlang”的东西。Pony 有着最引人注目的特性,它们是:
|
||||
|
||||
* 类型安全
|
||||
* 存储安全
|
||||
* 异常安全
|
||||
* 无数据竞争
|
||||
* 无死锁
|
||||
|
||||
|
||||
|
||||
此外,它被编译为高效的本地代码,它是在开放的情况下开发的,在 2-clause BSD 许可下可用。
|
||||
|
||||
以上说的功能不少,但在这里我将重点关注那些对我们公司来说采用 Pony 至关重要的功能。
|
||||
|
||||
### 为什么使用 Pony?
|
||||
|
||||
使用大多数我们现有的工具编写快速,安全,高效,高并发的程序并非易事。“快速,高效,高度并发”是可实现的目标,但加入“安全”之后,就困难了许多。通过 Wallaroo,我们希望同时实现四个目标,而 Pony 让实现它们更加简单。
|
||||
|
||||
#### 高并发
|
||||
|
||||
Pony 让并发变得简单。一部分是因为通过提供一个自用的并发主张。在 Pony 语言中,所有的并发都是通过 [Actor 模型][5] 进行的。
|
||||
|
||||
Actor 模型在 Erlang 和 Akka 中的实现最为著名。Actor 模型从 1970 年出现,细节因实施而异。不变的是,所有计算都由异步消息进行通信的 actor 来执行。
|
||||
|
||||
你可以用这种方式来看待 Actor 模型:面向对象中的对象是状态+同步方法,而 actor 是状态+异步方法。
|
||||
|
||||
当一个 actor 收到一个消息时,它执行相应的方法。该方法可以在只有该 actor 可访问的状态下运行。Actor 模型允许我们以并发安全的方式使用可变状态。每个 actor 都是单线程的。actor 中的两个方法不会并发运行。这意味着,在给定的 actor 中,数据更新不会引起数据竞争或通常与线程和可变状态相关的其他问题。
|
||||
|
||||
#### 快速高效
|
||||
|
||||
Pony actor 安排了一个高效的工作窃取调度程序。每个可用的 CPU 都有一个 Pony 调度程序。这种每个核心一个线程的并发模型是 Pony 尝试与 CPU 协同工作以尽可能高效运行的一部分。Pony 运行时尝试尽可能保持 CPU 缓存。代码越少,缓存越高,运行得越好。Pony 意在帮你的代码与 CPU 缓存友好相处。
|
||||
|
||||
Pony 运行时还会有每个 actor 的堆,因此在垃圾收集期间,没有“stop the world”的垃圾收集步骤。这意味着你的程序总是至少能做一点工作。因此 Pony 程序最终具有非常一致的性能和可预测的延迟。
|
||||
|
||||
#### 安全
|
||||
|
||||
Pony 型别系统引入了一个新概念:参考能力使得数据安全成为型别系统的一部分。Pony 语言中每种变量的类型都包含了有关如何在 actor 之间分享数据的信息。Pony 编译器用这些信息来确认,在编译时,你的代码是数据竞争和无死锁的。
|
||||
|
||||
如果这听起来有点像 Rust,那是因为本来就是这样的。Pony 的参考功能和 Rust 的借用检查器都提供数据安全性;它们只是以不同的方式来接近它,并有不同的权衡。
|
||||
|
||||
### Pony 适合你吗?
|
||||
|
||||
决定是否要在一个非业余爱好的项目上使用一门新的编程语言是困难的。与其他方法想比,你必须权衡工具的适当性和不成熟度。那么,Pony 和你搭不搭呢?
|
||||
|
||||
如果你有一个困难的并发问题需要解决,那么 Pony 可能是一个好选择。解决并发应用问题是 Pony 存在的理由。如果你能用一个单线程的 Python 脚本就完成所需操作,那你大概不需要它。如果你有一个困难的并发问题,你应该考虑 Pony 及其强大的无数据竞争,并发感知型别系统。
|
||||
|
||||
你将获得一个编译器,它将阻止你引入许多与并发相关的错误,并在运行时为你提供出色的性能特征。
|
||||
|
||||
### 开始使用 Pony
|
||||
|
||||
如果你准备好开始使用 Pony,你需要先在 Pony 的网站上访问 [学习部分][6]。在这里你会找到安装 Pony 编译器的步骤和学习这门语言的资源。
|
||||
|
||||
如果你愿意为你正在使用的语言做出贡献,我们会在 GitHub 上为你提供一些 [初学者友好的问题][7]。
|
||||
|
||||
同时,我迫不及待地想在 [我们的 IRC 频道][8] 和 [Pony 邮件列表][9] 上与你交谈。
|
||||
|
||||
要了解更多有关 Pony 的消息,请参阅 Sean Allen 2018 年 7 月 16 日至 19 日在俄勒冈州波特兰举行的 [第 20 届 OSCON 会议][11] 上的演讲: [Pony,我如何学会停止担心并拥抱未经证实的技术][10]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/5/pony
|
||||
|
||||
作者:[Sean T Allen][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[beamrolling](https://github.com/beamrolling)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/seantallen
|
||||
[1]:http://www.wallaroolabs.com/
|
||||
[2]:https://github.com/wallaroolabs/wallaroo
|
||||
[3]:https://www.ponylang.org/
|
||||
[4]:https://blog.wallaroolabs.com/2017/10/why-we-used-pony-to-write-wallaroo/
|
||||
[5]:https://en.wikipedia.org/wiki/Actor_model
|
||||
[6]:https://www.ponylang.org/learn/
|
||||
[7]:https://github.com/ponylang/ponyc/issues?q=is%3Aissue+is%3Aopen+label%3A%22complexity%3A+beginner+friendly%22
|
||||
[8]:https://webchat.freenode.net/?channels=%23ponylang
|
||||
[9]:https://pony.groups.io/g/user
|
||||
[10]:https://conferences.oreilly.com/oscon/oscon-or/public/schedule/speaker/213590
|
||||
[11]:https://conferences.oreilly.com/oscon/oscon-or
|
Loading…
Reference in New Issue
Block a user