<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Operating System | Easton Man's Blog</title>
	<atom:link href="https://blog.eastonman.com/blog/tag/operating-system/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.eastonman.com</link>
	<description>临渊羡鱼，不如退而结网</description>
	<lastBuildDate>Wed, 07 Sep 2022 10:22:09 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.5</generator>

<image>
	<url>https://blog.eastonman.com/wp-content/uploads/2021/02/cropped-Logo-e1613298891313-32x32.png</url>
	<title>Operating System | Easton Man's Blog</title>
	<link>https://blog.eastonman.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>xv6操作系统实验 &#8211; 质数筛</title>
		<link>https://blog.eastonman.com/blog/2020/11/xv6-primes/</link>
					<comments>https://blog.eastonman.com/blog/2020/11/xv6-primes/#comments</comments>
		
		<dc:creator><![CDATA[Easton Man]]></dc:creator>
		<pubDate>Fri, 13 Nov 2020 14:37:20 +0000</pubDate>
				<category><![CDATA[技术]]></category>
		<category><![CDATA[Operating System]]></category>
		<category><![CDATA[xv6]]></category>
		<guid isPermaLink="false">https://blog.eastonman.com/?p=254</guid>

					<description><![CDATA[<p>哈工大深圳2020年秋季操作系统实验课，利用管道实现质数筛的思路分析和ANSI C实现。</p>
The post <a href="https://blog.eastonman.com/blog/2020/11/xv6-primes/">xv6操作系统实验 – 质数筛</a> first appeared on <a href="https://blog.eastonman.com">Easton Man's Blog</a>.]]></description>
										<content:encoded><![CDATA[<p class="wpwc-reading-time">预计阅读时间： 5 分钟</p>
<p>哈工大深圳2020年秋季操作系统实验课，利用管道实现质数筛的思路分析和ANSI C实现。</p>



<p>Update 2022-09-07: xv6-2020及以后的xv6操作系统系统调用参数有小幅修改，因此本文中的代码并不能直接使用，仅作为思路的参考。</p>



<h2 class="wp-block-heading">管道概念</h2>



<p>管道是类Unix系统中重要的概念，它允许进程间的同步通信，是操作系统组成中必不可少的一部分。</p>



<h3 class="wp-block-heading">简单的管道用法</h3>



<p>此处参考一段<a href="https://zh.wikipedia.org/wiki/%E7%AE%A1%E9%81%93_(Unix)" target="_blank" rel="noreferrer noopener nofollow">维基百科</a>的示例。</p>



<pre class="wp-block-code"><code>ls -l | less</code></pre>



<p>在这个例子中，<code>ls</code>用于在Unix下列出目录内容，<code>less</code>是一个有搜索功能的交互式的文本分页器。这个管线使得用户可以在列出的目录内容比屏幕长时目录上下翻页。</p>



<p>以<code>less</code>结束的管道（或more，这是个相似的标签页工具）是最常被使用的。这让用户可以阅览尚未显示的大量文字（受可用缓存限制，控制台的屏幕大小、屏幕缓存大小往往有限，不足以一次先输出所有输出内容，也不能自由滚动内容），若少了这工具则这些文字将会卷过终端而无法阅读到。换句话说，他们将程序员从为自己的软件开发分页器的负担中解放了出来：他们只需要把他们的输出用过“管道”导入到<code>less</code>程序中即可，甚至也可以完全不顾分页问题，去假定他们的用户会在需要将输出分页的时候自己去这样做。</p>



<h3 class="wp-block-heading">在POSIX程序中使用管道</h3>



<p>使用C语言在UNIX中使用pipe(2)系统调用时，这个函数会让系统构建一个匿名管道，这样在进程中就打开了两个新的文件描述符：一个只读端和一个只写端。管道的两端是两个普通的文件描述符，它们是匿名的，只能够通过参数传递或使用dup系统调用复制，这就让其他进程无法连接该管道。 为了避免死锁，并充分利用进程的并行化，有一个或多个管道的UNIX进程通常会调用<code>fork(2)</code>产生新进程。并且每个子进程在开始读或写管道之前都会关掉不会用到的管道端。或者进程会产生一个子线程并使用管道来让线程进行数据交换。</p>



<p>注意：关闭不需要使用的管道端口不是必须的，但是是建议的，因为未关闭的管道可能会带来意想不到的问题。</p>



<h2 class="wp-block-heading">xv6中的管道</h2>



<p>xv6中的shell支持类似bash的管道，通过|传递字节流。系统调用与POSIX类似，我们很快可以看到，xv6系统也使用int类型作为文件描述符。</p>



<p>打开管道的代码就像这样。</p>



<pre class="wp-block-code"><code>int p&#91;2];
pipe(p);</code></pre>



<p>然后我们就可以对这个管道进行读写了，像这样。</p>



<pre class="wp-block-code"><code>char buff;
write(p&#91;1], "a", 1);
read(p&#91;0], &amp;buff, 1);</code></pre>



<p>特别注意，写入管道是非阻塞的，读取管道是阻塞的，一直到有数据到来或者管道被关闭。</p>



<h2 class="wp-block-heading">质数筛原理</h2>



<p>我们在此使用的是埃氏筛，而不是高斯筛。埃氏筛的介绍我搬运一段维基百科的GIF。</p>



<figure class="wp-block-image aligncenter size-large"><a href="https://zh.wikipedia.org/wiki/File:Sieve_of_Eratosthenes_animation.gif"><img fetchpriority="high" decoding="async" width="350" height="290" src="https://blog.eastonman.com/wp-content/uploads/2020/11/image.gif" alt="" class="wp-image-271"/></a></figure>



<p>简单的来说就是从头开始选取未被筛去的数，将它的倍数筛去，不断重复。</p>



<h2 class="wp-block-heading">利用管道的质数筛</h2>



<figure class="wp-block-image aligncenter size-large"><img decoding="async" width="448" height="233" src="https://blog.eastonman.com/wp-content/uploads/2020/11/image-20201017231043674.png" alt="" class="wp-image-275" srcset="https://blog.eastonman.com/wp-content/uploads/2020/11/image-20201017231043674.png 448w, https://blog.eastonman.com/wp-content/uploads/2020/11/image-20201017231043674-300x156.png 300w" sizes="(max-width: 448px) 100vw, 448px" /></figure>



<p>从主进程开始，不断新建子进程，每个子进程执行一次筛选，并将使用的基（base）认为是质数（这是正确的，请思考为什么），并返回，直到全部的数都被筛去或被返回。</p>



<p>各个进程之间的通讯将会使用到管道。</p>



<h2 class="wp-block-heading">详细的设计思路</h2>



<figure class="wp-block-image size-large"><img decoding="async" src="https://blog.eastonman.com/wp-content/uploads/2020/11/xv6-prime-filter.svg" alt="" class="wp-image-256"/></figure>



<h2 class="wp-block-heading">实现源码</h2>



<p>Let&#8217;s start coding!</p>



<pre class="wp-block-code"><code>#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

void prime(int input_fd);

int main(int argc, char const *argv&#91;])
{
    int parent_fd&#91;2];
    pipe(parent_fd);
    if (fork())
    {
        close(parent_fd&#91;0]);
        int i;
        for (i = 2; i &lt; 36; i++)
        {
            write(parent_fd&#91;1], &amp;i, sizeof(int));
        }
        close(parent_fd&#91;1]);
    }
    else
    {
        close(parent_fd&#91;1]);
        prime(parent_fd&#91;0]);
    }
    wait();
    exit();
}

void prime(int input_fd)
{
    int base;
    /* Exit if last child */
    if (read(input_fd, &amp;base, sizeof(int)) == 0)
    {
        exit();
    }
    printf("prime %d\n", base);

    /* Create new child if not last */
    int p&#91;2];
    pipe(p);
    if (fork() == 0)
    {
        close(p&#91;1]);
        prime(p&#91;0]);
    }
    else
    {
        close(p&#91;0]);
        int n;
        int eof;
        do
        {
            eof = read(input_fd, &amp;n, sizeof(int));
            if (n % base != 0)
            {
                write(p&#91;1], &amp;n, sizeof(int));
            }
        } while (eof);

        close(p&#91;1]);
    }
    wait();
    exit();
}</code></pre>The post <a href="https://blog.eastonman.com/blog/2020/11/xv6-primes/">xv6操作系统实验 – 质数筛</a> first appeared on <a href="https://blog.eastonman.com">Easton Man's Blog</a>.]]></content:encoded>
					
					<wfw:commentRss>https://blog.eastonman.com/blog/2020/11/xv6-primes/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
	</channel>
</rss>
