<?php
/**
 * ============================================================
 *  现代操作系统 · 第八章《多处理器系统》大白话 + 代码例子
 * ============================================================
 *  作用:30 个多处理器/多计算机/分布式概念,每条 = 大白话 + PHP 代码示例。
 *  说明:多为硬件结构与并行/分布式机制,用 PHP 代码模拟其思想。
 *  运行:php multiprocessor.php            全部
 *        php multiprocessor.php 308        看第 308 条(RPC)
 *        php multiprocessor.php 调度        关键词搜索
 * ============================================================
 */

declare(strict_types=1);

final class Topic
{
    public function __construct(
        public readonly int $no,
        public readonly string $title,
        public readonly string $plain,
        public readonly string $code
    ) {}
}

final class MultiprocessorBook
{
    /** @var Topic[] */
    private array $topics = [];

    public function __construct()
    {
        $this->load();
    }

    private function load(): void
    {
        $data = [
            290 => ['多处理器系统硬件',
                '一台机器里装多个 CPU,它们共享同一份内存,靠总线或交换网络连起来一起干活。',
                <<<'CODE'
$system = [
    'cpus'   => ['cpu0', 'cpu1', 'cpu2', 'cpu3'],
    'memory' => 'shared',             // 共享同一份内存
    'connect'=> 'bus',                // 靠总线/交换网络互连
];
CODE],

            291 => ['UMA 多处理器',
                '统一内存访问:每个 CPU 访问任何内存的速度都一样(对称、好编程,但总线易堵)。',
                <<<'CODE'
function umaAccessTime($cpu, $addr) {
    return 100;                       // 不管哪个CPU、哪块内存, 延迟都一样
}
echo umaAccessTime('cpu0', 0x1000);   // 100
echo umaAccessTime('cpu3', 0xFFFF);   // 100 (相同)
CODE],

            292 => ['NUMA 多处理器',
                '非统一内存访问:每个 CPU 有"近"内存()"远"内存(),扩展性好但要会就近放数据。',
                <<<'CODE'
function numaAccessTime($cpu, $memNode) {
    return $cpu == $memNode ? 100 : 300; // 本地内存快, 远端慢3倍
}
echo numaAccessTime(0, 0);            // 100 本地
echo numaAccessTime(0, 3);            // 300 远端
CODE],

            293 => ['多处理器操作系统类型',
                '管多 CPU 的三种思路:各管各的、一主多从、全对称(SMP)。',
                <<<'CODE'
$osTypes = [
    'private'      => '每个CPU一套独立OS',
    'master_slave' => '一个主CPU管全部',
    'smp'          => '所有CPU平等共享一套OS',
];
CODE],

            294 => ['每个 CPU 有自己的操作系统',
                '把内存切块,每个 CPU 跑一份独立 OS,互不通气;简单但资源没法共享、负载不均。',
                <<<'CODE'
$cpus = [
    0 => ['os' => 'copy0', 'mem' => '0-1G'],   // 各跑各的OS
    1 => ['os' => 'copy1', 'mem' => '1-2G'],
];
// 缺点: cpu0 忙死, cpu1 闲死, 无法互相帮忙
CODE],

            295 => ['主从多处理器',
                '一个主 CPU 专门跑操作系统和调度,其它从 CPU 只跑用户程序;主 CPU 易成瓶颈。',
                <<<'CODE'
function masterSlave($task, &$cpus) {
    if ($task['type'] == 'syscall')
        $cpus['master']->handle($task);   // 系统调用全交给主CPU
    else
        $cpus['slave'][0]->run($task);     // 用户程序丢给从CPU
}
CODE],

            296 => ['对称多处理器 SMP',
                '所有 CPU 平等,都能跑 OS 也能跑用户程序,用锁保护内核共享数据;现代主流。',
                <<<'CODE'
$kernelLock = false;
function smpEnterKernel(&$lock) {
    while (!compareAndSwap($lock, false, true)) { /* 自旋等 */ }
    // 进入内核临界区, 任意CPU都平等竞争
}
function smpLeaveKernel(&$lock) { $lock = false; }
CODE],

            297 => ['多处理器同步',
                '多个 CPU 同时改一份数据要同步;单机的关中断没用了,得靠原子指令(TSL/CAS)。',
                <<<'CODE'
function atomicTSL(&$lock) {           // 硬件原子: 多CPU也安全
    $old = $lock; $lock = 1; return $old;
}
// 多CPU场景: 关中断无效, 必须用总线锁定的原子指令
CODE],

            298 => ['自旋锁与忙等待',
                '锁占用时间极短时,CPU 原地打转反复试(自旋)比睡眠唤醒更划算,省掉切换开销。',
                <<<'CODE'
function spinLock(&$lock) {
    while (atomicTSL($lock) != 0) {
        // 原地自旋, 不睡 (切换比短暂等待还贵)
    }
}
function spinUnlock(&$lock) { $lock = 0; }
CODE],

            299 => ['多处理器调度',
                '不仅要决定"跑哪个进程",还要决定"在哪个 CPU 上跑",且尽量别乱迁移(伤缓存)。',
                <<<'CODE'
function schedule($proc, $cpus) {
    // 优先放回上次跑的CPU (亲和性, 缓存还热)
    return $proc['lastCpu'] ?? leastBusy($cpus);
}
CODE],

            300 => ['时间共享调度',
                '所有 CPU 共用一个就绪队列,谁空了就来队列里抓一个跑;简单但队列要加锁、伤亲和性。',
                <<<'CODE'
$readyQueue = new SplQueue();
function timeSharing(&$queue, $cpu) {
    lock($queue);
    $proc = $queue->isEmpty() ? null : $queue->dequeue(); // 共享队列抓一个
    unlock($queue);
    if ($proc) $cpu->run($proc);
}
CODE],

            301 => ['空间共享调度',
                '把相关的一组线程一次性分给一批 CPU 同时跑,跑完才换,适合要紧密协作的并行程序。',
                <<<'CODE'
function spaceSharing($threadGroup, $cpus) {
    foreach ($threadGroup as $i => $thread)
        $cpus[$i]->assign($thread);    // 一组线程占住一批CPU
    // 全组一起跑, 不被打散
}
CODE],

            302 => ['群调度',
                '空间+时间结合:把一组协作线程"成群"地同时调度上 CPU,让它们能互相即时通信。',
                <<<'CODE'
function gangSchedule($gang, $cpus, $timeSlice) {
    foreach ($gang as $i => $thread)
        $cpus[$i]->run($thread, $timeSlice); // 整群同一时间片一起上
    // 它们能即时互相通信, 不会一个在跑一个在等
}
CODE],

            303 => ['多计算机硬件',
                '多台独立计算机(各有自己内存)用高速网络连起来,又叫集群;不共享内存,靠收发消息。',
                <<<'CODE'
$cluster = [
    'node0' => ['cpu'=>1, 'mem'=>'private'], // 各有私有内存
    'node1' => ['cpu'=>1, 'mem'=>'private'],
    'link'  => 'high-speed network',          // 靠网络连
];
CODE],

            304 => ['互连技术',
                '节点怎么连:网格、超立方体、环、树等拓扑,影响通信距离和带宽。',
                <<<'CODE'
$topologies = [
    'grid'      => '网格, 邻居相连',
    'hypercube' => '超立方体, 距离短',
    'ring'      => '环形',
    'tree'      => '树形',
];
CODE],

            305 => ['网络接口',
                '每个节点有块网卡负责收发包,自带缓冲和处理器,减轻主 CPU 的通信负担。',
                <<<'CODE'
$nic = [
    'sendBuffer' => [],               // 发送缓冲
    'recvBuffer' => [],               // 接收缓冲
    'onboardCpu' => true,             // 网卡自带处理器, 分担主CPU
];
CODE],

            306 => ['低层通信软件',
                '直接操作网卡收发包的底层代码,追求零拷贝、少干预,把数据快速送进送出。',
                <<<'CODE'
function lowLevelSend($nic, $packet) {
    $nic['sendBuffer'][] = $packet;   // 直接塞进网卡缓冲
    $nic['trigger']();                // 触发硬件发送(尽量零拷贝)
}
CODE],

            307 => ['用户层通信软件',
                '给程序用的收发接口:send/receive 原语,分阻塞(等到完成)和非阻塞(立即返回)。',
                <<<'CODE'
function send($dest, $msg, $blocking = true) {
    enqueueToNic($dest, $msg);
    if ($blocking) waitUntilSent();   // 阻塞: 等发完才返回
    // 非阻塞: 立即返回, 后台慢慢发
}
function receive($src) { return blockUntilArrive($src); }
CODE],

            308 => ['远程过程调用 RPC',
                '让调远程机器上的函数像调本地函数一样:参数打包发过去,执行后结果传回来。',
                <<<'CODE'
function rpcCall($host, $func, $args) {
    $request  = serialize(['func'=>$func, 'args'=>$args]); // 客户端打包(marshal)
    $response = sendToServer($host, $request);             // 发到远端执行
    return unserialize($response);                         // 拆包返回结果
}
$sum = rpcCall('node1', 'add', [3, 5]); // 像本地调用一样
CODE],

            309 => ['分布式共享存储器 DSM',
                '多台无共享内存的机器,靠软件假装出一片"共享内存",按页在网络上搬来搬去。',
                <<<'CODE'
function dsmAccess($page, $localPages, $remoteNodes) {
    if (isset($localPages[$page])) return $localPages[$page]; // 本地有
    $data = fetchPageOverNetwork($page, $remoteNodes);        // 没有就网络抓页
    $localPages[$page] = $data;       // 缓存到本地
    return $data;
}
CODE],

            310 => ['多计算机调度',
                '不光排时间,还要决定每个进程放到哪台机器上跑,尽量减少跨机通信。',
                <<<'CODE'
function placeProcess($proc, $nodes) {
    // 把通信频繁的进程放同一台机, 减少网络往返
    return $proc['talksTo']
        ? sameNodeAs($proc['talksTo'])
        : leastLoaded($nodes);
}
CODE],

            311 => ['负载平衡',
                '别让有的机器忙死有的闲死;把任务从重载节点挪到轻载节点,分发送/接收两种发起方式。',
                <<<'CODE'
function loadBalance(&$nodes) {
    $busy = maxLoad($nodes); $idle = minLoad($nodes);
    if ($nodes[$busy]['load'] - $nodes[$idle]['load'] > 2) {
        $task = array_pop($nodes[$busy]['tasks']);
        $nodes[$idle]['tasks'][] = $task;   // 重载挪给轻载
    }
}
CODE],

            312 => ['分布式系统',
                '一堆联网的独立计算机,对用户却像一台机器;比多计算机更松散、跨地域、异构。',
                <<<'CODE'
$distributed = [
    'nodes'       => ['北京', '上海', '广州'], // 跨地域
    'transparent' => true,            // 用户感觉像用一台机
    'coupling'    => 'loose',         // 松耦合, 各自独立
];
CODE],

            313 => ['网络硬件',
                '连接分布式节点的物理网络:以太网(局域)、广域网、交换机路由器等。',
                <<<'CODE'
$networkHardware = [
    'LAN'    => '以太网, 局域, 高速',
    'WAN'    => '广域网, 跨城市/国家',
    'switch' => '交换机, 局域内转发',
    'router' => '路由器, 网络间选路',
];
CODE],

            314 => ['网络服务与协议',
                '通信要守共同规矩(协议):分层(如 TCP/IP),各层管各的事,下层给上层提供服务。',
                <<<'CODE'
$stack = [
    'application' => 'HTTP/FTP',      // 应用层
    'transport'   => 'TCP/UDP',       // 传输层(可靠/不可靠)
    'network'     => 'IP',            // 网络层(寻址路由)
    'link'        => 'Ethernet',      // 链路层
];
CODE],

            315 => ['中间件',
                '架在操作系统和应用之间的一层软件,抹平各机器差异,提供统一的分布式编程模型。',
                <<<'CODE'
// 中间件: 让上层应用不用管底下是什么OS/网络
class Middleware {
    public function call($service, $args) {
        return $this->locate($service)->invoke($args); // 屏蔽分布细节
    }
}
CODE],

            316 => ['基于文档的中间件',
                '把信息组织成互相超链接的文档,靠 URL 定位、点链接跳转,万维网就是典型。',
                <<<'CODE'
// Web 模型: 文档 + 超链接 + URL
$page = [
    'url'   => 'http://site/a.html',
    'links' => ['http://site/b.html', 'http://other/c.html'], // 超链接跳转
];
CODE],

            317 => ['基于文件系统的中间件',
                '把整个分布式系统做成一个大文件系统,远程文件像本地文件一样读写(如 NFS)。',
                <<<'CODE'
// 远程文件当本地用 (类似 NFS 挂载)
mount('node1:/data', '/mnt/remote');  // 挂载远程目录
$content = file_get_contents('/mnt/remote/a.txt'); // 像读本地文件
CODE],

            318 => ['基于对象的中间件',
                '把远程资源封装成对象,调用远程对象的方法像调用本地对象(如 CORBA、Java RMI)。',
                <<<'CODE'
// 远程对象: 拿到代理, 调方法像本地一样
$remoteObj = $orb->resolve('BankAccount@node2');
$remoteObj->deposit(100);             // 实际在远端机器上执行
CODE],

            319 => ['基于协作的中间件',
                '面向"协调与共享"的模型,如发布/订阅、共享元组空间(Linda),让进程松耦合地交流。',
                <<<'CODE'
// 元组空间 (Linda 模型): 谁都能丢/取数据, 不需直接认识对方
$tupleSpace = [];
function out(&$ts, $tuple) { $ts[] = $tuple; }         // 发布
function in(&$ts, $pattern) {                          // 按模式取走
    foreach ($ts as $k => $t)
        if (match_pattern($t, $pattern)) { unset($ts[$k]); return $t; }
}
CODE],
        ];

        foreach ($data as $no => [$title, $plain, $code]) {
            $this->topics[$no] = new Topic($no, $title, $plain, $code);
        }
    }

    public function renderAll(): void
    {
        $this->printHeader('现代操作系统 · 第八章《多处理器系统》大白话 + 代码例子');
        foreach ($this->topics as $t) $this->printTopic($t);
        $this->printFooter(count($this->topics));
    }

    public function renderOne(int $no): void
    {
        if (!isset($this->topics[$no])) {
            echo "⚠️  没有第 {$no} 条(本章 290~319)\n";
            return;
        }
        $this->printHeader("第 {$no} 条");
        $this->printTopic($this->topics[$no]);
    }

    public function search(string $kw): void
    {
        $hit = array_filter(
            $this->topics,
            fn(Topic $t) => mb_strpos($t->title, $kw) !== false
                         || mb_strpos($t->plain, $kw) !== false
                         || mb_strpos($t->code, $kw) !== false
        );
        if (!$hit) { echo "🔍 没找到包含“{$kw}”的条目\n"; return; }
        $this->printHeader("搜索“{$kw}”,命中 " . count($hit) . " 条");
        foreach ($hit as $t) $this->printTopic($t);
    }

    private function printHeader(string $title): void
    {
        echo "\n" . str_repeat('=', 62) . "\n  {$title}\n" . str_repeat('=', 62) . "\n";
    }

    private function printTopic(Topic $t): void
    {
        printf("\n【%03d】%s\n", $t->no, $t->title);
        echo "  ▷ 大白话:" . wordwrap_cn($t->plain, 36, "\n            ") . "\n";
        echo "  ▶ 代码例子:\n";
        foreach (explode("\n", $t->code) as $line) {
            echo "      | " . $line . "\n";
        }
    }

    private function printFooter(int $count): void
    {
        echo "\n" . str_repeat('-', 62) . "\n";
        echo "  共 {$count} 条,每条含“大白话 + PHP代码例子”。\n";
        echo str_repeat('-', 62) . "\n";
    }
}

/** 中文换行 */
function wordwrap_cn(string $text, int $width, string $break): string
{
    $len = mb_strlen($text);
    if ($len <= $width) return $text;
    $out = '';
    for ($i = 0; $i < $len; $i += $width) {
        $out .= mb_substr($text, $i, $width);
        if ($i + $width < $len) $out .= $break;
    }
    return $out;
}

// ===================== 入口 =====================
$book = new MultiprocessorBook();
$arg = $argv[1] ?? null;
if ($arg === null)            $book->renderAll();
elseif (ctype_digit($arg))    $book->renderOne((int) $arg);
else                          $book->search($arg);
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐