mirror of
https://github.com/MPSU/APS.git
synced 2025-09-16 01:30:10 +00:00
Корректировка конспектов лекций (#131)
* Корректировки конспектов лекций * Корректировка конспекта лекции 5 * Корректировка конспекта лекции 8 * Корректировка конспекта лекции 9 * Корректировка конспекта лекции 10 * Корректировка конспекта лекции 11 * Корректировка конспекта лекции 12 * Корректировка конспекта лекции 13 * Корректировка конспекта лекции 12 * Корректировка конспекта лекции 14 * Корректировка конспекта лекции 16 * Корректировка конспекта лекции 17 * Корректировка конспекта лекции * Корректировка конспекта лекции 20 * Корректировка конспекта лекции 21 * Корректировка конспекта лекции 22 * Корректировка конспекта лекции 23 * Корректировка конспекта лекции 13 * Корректировка конспекта лекции 12 * Корректировка конспекта лекции 20
This commit is contained in:
@@ -54,16 +54,16 @@
|
||||
|
||||
### Коммуникационные модели
|
||||
|
||||
В коммуникационной моделью с общей памятью есть:
|
||||
В коммуникационной модели с общей памятью есть:
|
||||
|
||||
- есть единое адресное пространство для потоков;
|
||||
- единое адресное пространство для потоков;
|
||||
- общение между потоками происходит через неявную связь с помощью загрузки и сохранения в память.
|
||||
|
||||

|
||||
|
||||
*Рис. 1. Коммуникационная модель с общей памятью.*
|
||||
|
||||
В коммуникационной моделью с обменом сообщениями присутствуют:
|
||||
В коммуникационной модели с обменом сообщениями присутствуют:
|
||||
|
||||
- разделенное адресное пространство (у каждого из процессоров своя память);
|
||||
- общение между потоками происходит явной связи путем отправки и получения сообщений.
|
||||
@@ -87,11 +87,11 @@
|
||||
|
||||
Рассмотрим ситуацию, когда процесс порождает два параллельных потока `P₁` и `P₂` и впоследствии использует результаты их вычислений. После создания, процесс сможет продолжить дальнейшее выполнение только когда будут выполнены оба потока, а значит есть необходимость их синхронизировать.
|
||||
|
||||
- Проиводитель-потребитель (producer-consumer): потребительский процесс должен ждать, пока процесс производителя не произведет данные (то есть потребитель не может продолжать выполнение, пока производитель не произведёт какие-то данные).
|
||||
- Производитель-потребитель (producer-consumer): потребительский процесс должен ждать, пока процесс производителя не произведет данные (то есть потребитель не может продолжать выполнение, пока производитель не произведёт какие-то данные).
|
||||
|
||||

|
||||
|
||||
*Рис. 4. Способ синхронизации параллельных процессов "Проиводитель-потребитель" (producer-consumer).
|
||||
*Рис. 4. Способ синхронизации параллельных процессов "Проиводитель-потребитель" (producer-consumer).*
|
||||
|
||||
- **Взаимное исключение**: операционная система должна гарантировать, что ресурс используется только одним процессом в данный момент времени (например, два процесса не могут одновременно обращаться к одной ячейке памяти).
|
||||
|
||||
@@ -109,17 +109,17 @@
|
||||
|
||||

|
||||
|
||||
*Рис. 5. Пример программы с синхронной связью.
|
||||
*Рис. 5. Пример программы с синхронной связью.*
|
||||
|
||||
Метка `loop` указывает на последовательность инструкций xxxᵢ, которые генерируют данные `с`. После этого производитель оправляет эти данные для потребителя и потом возвращается к началу цикла и так далее. В свою очередь потребитель получает данные (receive) от производителя, выполняет над ними нужные операции и снова возвращается к началу цикла.
|
||||
Метка `loop` указывает на последовательность инструкций `xxxᵢ`, которые генерируют данные `с`. После этого производитель оправляет эти данные для потребителя и потом возвращается к началу цикла и так далее. В свою очередь потребитель получает данные (receive) от производителя, выполняет над ними нужные операции и снова возвращается к началу цикла.
|
||||
|
||||
**Приоритет очерёдности** `a`⩽`b`,`a` предшествует `b`:
|
||||
|
||||
- Потребитель не может использовать данные до их получения (событие sendᵢ должно происходить раньше или в тот же момент времени, когда происходит `rcvᵢ` (получение) этих данных);
|
||||
- Потребитель не может использовать данные до их получения (событие `sendᵢ` должно происходить раньше или в тот же момент времени, когда происходит `rcvᵢ` (получение) этих данных);
|
||||
|
||||

|
||||
|
||||
*Рис. 6. Пример программы с синхронной связью c учётом приоритета очерёдности.
|
||||
*Рис. 6. Пример программы с синхронной связью c учётом приоритета очерёдности.*
|
||||
|
||||
- Производитель не может перезаписать данные до их использования потребителем (получение данных должно происходить раньше, чем их перезапишет следующая `i+1` посылка).
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
|
||||

|
||||
|
||||
*Рис. 7. Пример буфера FIFO без ограничений приоритета.
|
||||
*Рис. 7. Пример буфера FIFO без ограничений приоритета.*
|
||||
|
||||
Буфер FIFO ослабляет ограничения, связанные с синхронизацией. Производитель может опередить потребителя на `N` значений (где N — глубина данного буфера).
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
|
||||

|
||||
|
||||
*Рис. 8. Пример кольцевого буфера без ограничений приоритета с указателями на начало и конец очереди.
|
||||
*Рис. 8. Пример кольцевого буфера без ограничений приоритета с указателями на начало и конец очереди.*
|
||||
|
||||
У нас есть буфер на 3 элемента (очередь) и два указателя: один указывает на место, куда мы будем писать (`write_ptr`), а другой указывает на место, откуда мы будем читать (`read_ptr`). В очередной момент времени происходит генерация новых данных (`send c₀`) — они записываются в место, куда указывает `write_ptr`. После этого данный указатель сдвигается на одну ячейку вправо (`i+1`). Далее мы снимаем данные с первой ячейки (`rcv()`) c₀ и указатель `read_ptr` сдвигается на следующую ячейку (`c₁`) и так далее.
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
|
||||

|
||||
|
||||
*Рис. 9. Пример программы буфера FIFO с общей памятью без ограничений приоритета.
|
||||
*Рис. 9. Пример программы буфера FIFO с общей памятью без ограничений приоритета.*
|
||||
|
||||
Данный буфер **не применяет никаких ограничений приоритета** (*например, `rcv()` может быть вызван до любой отправки*) и поэтому работает неправильно. Чтобы устранить эту проблему, нам поможет концепция *семафоров*.
|
||||
|
||||
@@ -172,7 +172,7 @@ Semaphore — это тип данных, число ≥ 0.
|
||||
|
||||

|
||||
|
||||
*Рис. 10. Потоки `А` и `B` .
|
||||
*Рис. 10. Потоки `А` и `B` .*
|
||||
|
||||
Решение:
|
||||
|
||||
@@ -182,7 +182,7 @@ Semaphore — это тип данных, число ≥ 0.
|
||||
|
||||

|
||||
|
||||
*Рис. 11. Потоки `A` и `B` с семафорами для приоритета.
|
||||
*Рис. 11. Потоки `A` и `B` с семафорами для приоритета.*
|
||||
|
||||
Если мы в потоке B придём раньше до `B₄`, то `s` по умолчанию = 0 и мы застрянем на инструкции `wait(s)`. В это время первый поток А доходит до `signal(s)`, то есть увеличивает `s` на 1, соответственно внутри `wait` `s` тоже увеличилось на 1. Мы прошли этот `wait` и семафор снова стал нулём.Таким образом, мы получили синхронизацию, которую хотели.
|
||||
|
||||
@@ -208,16 +208,16 @@ Semaphore — это тип данных, число ≥ 0.
|
||||
|
||||

|
||||
|
||||
*Рис. 12. Пример программы буфера FIFO с семафорами.
|
||||
*Рис. 12. Пример программы буфера FIFO с семафорами.*
|
||||
|
||||
- выполняется приоритет, управляемый семафором `sendᵢ` ≤ `revᵢ`;
|
||||
- выполняется приоритет, управляемый семафором `sendᵢ` ≤ `rcvᵢ`;
|
||||
- здесь есть один ресурс, управляемый семафором: количество символов в буфере;
|
||||
- всё ещё некорректная ситуация, так как производитель может переполнить буфер;
|
||||
- должны применять требование `rcvᵢ` ≤ `sendᵢ₊₁>`.
|
||||
- должны применять требование `rcvᵢ` ≤ `sendᵢ₊₁`.
|
||||
|
||||

|
||||
|
||||
*Рис. 13. Пример программы буфера FIFO с семафорами с применением требования `rcvᵢ` ≤ `sendᵢ₊₁.`
|
||||
*Рис. 13. Пример программы буфера FIFO с семафорами с применением требования `rcvᵢ` ≤ `sendᵢ₊₁.`*
|
||||
|
||||
Ресурсы, управляемые семафорами: символы в FIFO, свободное место в FIFO.
|
||||
Работает с одним производителем и потребителем.
|
||||
@@ -228,7 +228,7 @@ Semaphore — это тип данных, число ≥ 0.
|
||||
|
||||

|
||||
|
||||
*Рис. 14. Код к конкретной задаче.
|
||||
*Рис. 14. Код к конкретной задаче.*
|
||||
|
||||
Результат: у вас есть 200 рублей и баланс счёта уменьшился на 200 рублей.
|
||||
|
||||
@@ -236,7 +236,7 @@ Semaphore — это тип данных, число ≥ 0.
|
||||
|
||||

|
||||
|
||||
*Рис. 15. Перекрытие потоков.
|
||||
*Рис. 15. Перекрытие потоков.*
|
||||
|
||||
Результат: у вас есть 200 рублей, а баланс счёта уменьшился на 100 рублей.
|
||||
|
||||
@@ -244,13 +244,13 @@ Semaphore — это тип данных, число ≥ 0.
|
||||
Для некоторых сегментов кода, называемых критическими секциями (**critical sections**) мы хотели бы убедиться, что никакие два выполнения не перекрываются.
|
||||
Это ограничение называется взаимным исключением (**mutual exclusion**).
|
||||
|
||||
**Решение**: внедрить в критические секции обёртки, которые гарантируют **атомарность**, то есть делают их похожими но отдельные мгновенные операции.
|
||||
**Решение**: внедрить в критические секции обёртки, которые гарантируют **атомарность**, то есть делают их похожими на отдельные мгновенные операции.
|
||||
|
||||
### Семафоры для взаимных исключений
|
||||
|
||||

|
||||
|
||||
*Рис. 16. Функция из предыдущего примера.
|
||||
*Рис. 16. Функция из предыдущего примера.*
|
||||
|
||||
Нам нужно гарантировать, что двойной вызов функции `debit` не пересекается. То есть либо `a` предшествует `b`, либо `b` предшествует `a` (они не пересекаются!).
|
||||
|
||||
@@ -262,7 +262,7 @@ Semaphore — это тип данных, число ≥ 0.
|
||||
|
||||

|
||||
|
||||
*Рис. 17. Итоговая функция с семафором для взаимных исключений.
|
||||
*Рис. 17. Итоговая функция с семафором для взаимных исключений.*
|
||||
|
||||
### Проблемы атомарности
|
||||
|
||||
@@ -271,13 +271,13 @@ Semaphore — это тип данных, число ≥ 0.
|
||||
|
||||

|
||||
|
||||
*Рис. 18. Потоки производители для нашего примера.
|
||||
*Рис. 18. Потоки производители для нашего примера.*
|
||||
|
||||
Справиться с этим помогут наши блокировки:
|
||||
|
||||

|
||||
|
||||
*Рис. 19. Программа буфера FIFO с блокировками.
|
||||
*Рис. 19. Программа буфера FIFO с блокировками.*
|
||||
|
||||
### Мощность семафора
|
||||
|
||||
@@ -293,7 +293,7 @@ Semaphore — это тип данных, число ≥ 0.
|
||||
|
||||

|
||||
|
||||
*Рис. 20. Итоговая программа буфера FIFO с блокировками для защиты переменных `in` и `out`.
|
||||
*Рис. 20. Итоговая программа буфера FIFO с блокировками для защиты переменных `in` и `out`.*
|
||||
|
||||
### Реализация семафоров
|
||||
|
||||
@@ -310,20 +310,21 @@ Semaphore — это тип данных, число ≥ 0.
|
||||
|
||||

|
||||
|
||||
*Рис. 21. Пересылка одинаковой суммой денег с одного счёта на другой.
|
||||
*Рис. 21. Пересылка одинаковой суммой денег с одного счёта на другой.*
|
||||
|
||||

|
||||
|
||||
*Рис. 22. Функция пересылки денег.
|
||||
*Рис. 22. Функция пересылки денег.*
|
||||
|
||||
Что же может пойти не так?
|
||||
|
||||
Thread 1: wait (lock [0903]); (поток 1 блокирует 0903)
|
||||
|
||||
Thread 2: wait (lock [1103]); (поток 2 параллельно блокирует 1103)
|
||||
|
||||
Thread 1: wait (lock [1103]); //не завершиться, пока не произойдёт signal 2 потока (заблокирован, потому что предыдущий поток его уже заблокировал, кончился ресурс)
|
||||
|
||||
Thread 1: wait (lock [0903]); //не завершиться, пока не произойдёт signal 1 потока.
|
||||
Thread 2: wait (lock [0903]); //не завершиться, пока не произойдёт signal 1 потока.
|
||||
|
||||
Ни один поток не может добиться прогресса - это называется **Тупик** или **Deadlock**.
|
||||
**Deadlock** — ситуация, при которой несколько процессов находятся в состоянии ожидания ресурсов, занятых друг другом, и ни один из них не может продолжать свое выполнение.
|
||||
@@ -332,9 +333,9 @@ Thread 1: wait (lock [0903]); //не завершиться, пока не пр
|
||||
|
||||

|
||||
|
||||
*Рис. 23. Карикатура обедающих философов за столом.
|
||||
*Рис. 23. Карикатура обедающих философов за столом.*
|
||||
|
||||
Философы мыслят глубокими мыслями, но имеют простые мирские потребности. Когда вы голодны, группа из `N` философов будет сидеть вокруг стола с N палочками для еды, разбросанными между ними. Еда подаётся, и каждый философ наслаждается неторопливой едой, используя палочки для еды с обеих сторон.
|
||||
Философы мыслят глубокими мыслями, но имеют простые мирские потребности. Когда вы голодны, группа из `N` философов будет сидеть вокруг стола с `N` палочками для еды, разбросанными между ними. Еда подаётся, и каждый философ наслаждается неторопливой едой, используя палочки для еды с обеих сторон.
|
||||
Они очень вежливы и терпеливы, и каждый соблюдает обеденный протокол.
|
||||
Алгоритмы философа:
|
||||
|
||||
@@ -364,7 +365,7 @@ Thread 1: wait (lock [0903]); //не завершиться, пока не пр
|
||||
|
||||

|
||||
|
||||
*Рис. 24. Решение проблемы обедающих философов.
|
||||
*Рис. 24. Решение проблемы обедающих философов.*
|
||||
|
||||
Доказательство: `Deadlock` означает, что каждый философ ждёт ресурса, которым владеет какой-то другой философ. Но философ, держащий самую большую палочку для еды не может ждать какого-либо другого философа.
|
||||
|
||||
@@ -372,13 +373,13 @@ Thread 1: wait (lock [0903]); //не завершиться, пока не пр
|
||||
|
||||

|
||||
|
||||
*Рис. 25. Исправленный метод передачи денежной суммы.
|
||||
*Рис. 25. Исправленный метод передачи денежной суммы.*
|
||||
|
||||
## Многоядерность
|
||||
|
||||

|
||||
|
||||
*Рис. 26. Многоядерность.
|
||||
*Рис. 26. Многоядерность.*
|
||||
|
||||
1. Современные процессоры обычно имеют от 2 до 8 ядер, где каждое ядро имеет собственный кэш для повышения производительности.
|
||||
2. Ядро могут использоваться совместно для ускорения работы приложения.
|
||||
@@ -392,7 +393,7 @@ Thread 1: wait (lock [0903]); //не завершиться, пока не пр
|
||||
|
||||

|
||||
|
||||
*Рис. 27. Проблема многоядерности.
|
||||
*Рис. 27. Проблема многоядерности.*
|
||||
|
||||
1) Ядро 0 загружает данные из памяти по адресу `A` число два.
|
||||
2) Ядро 2 выгружает в память по адресу `A` число три.
|
||||
@@ -418,7 +419,7 @@ Thread 1: wait (lock [0903]); //не завершиться, пока не пр
|
||||
Протоколы когерентности должны обеспечивать соблюдение двух правил:
|
||||
|
||||
- распространяющаяся запись (**Write propagation**): записи в конечном итоге становятся видимыми для всех процессоров (если кто-то из процессоров пишет куда-то, то нужно однозначно остальным об этом сообщить);
|
||||
сериализация записи (**Write serialization**): записи в одно и то же место сериализуются (все процессоры видят их в том же порядке).
|
||||
- сериализация записи (**Write serialization**): записи в одно и то же место сериализуются (все процессоры видят их в том же порядке).
|
||||
|
||||
Как обеспечить распространение записи:
|
||||
|
||||
@@ -436,7 +437,7 @@ Thread 1: wait (lock [0903]); //не завершиться, пока не пр
|
||||
|
||||

|
||||
|
||||
*Рис. 28. Процессоры со `Snoopy Cache`, которые подключены к основной памяти.
|
||||
*Рис. 28. Процессоры со `Snoopy Cache`, которые подключены к основной памяти.*
|
||||
|
||||
То есть каждый раз, когда процессор обращается к кэш памяти, он выставляет информацию на общую шину. И все кэши видят когда кто-то на эту шину выставляет информацию.
|
||||
|
||||
@@ -452,7 +453,7 @@ Snoopy кэш отличается от обычного кэша наличие
|
||||
|
||||

|
||||
|
||||
*Рис. 29. Упрощенная форма `Snoopy Cache`.
|
||||
*Рис. 29. Упрощенная форма `Snoopy Cache`.*
|
||||
|
||||
**Snoopy протокол (FSM)** — это конечный автомат, который зависит от того что происходит на шине и обновляет значения состояния.
|
||||
|
||||
@@ -465,14 +466,14 @@ Snoopy кэш отличается от обычного кэша наличие
|
||||
|
||||

|
||||
|
||||
*Рис. 30. Протокол `VI`.
|
||||
*Рис. 30. Протокол `VI`.*
|
||||
|
||||
Когда мы находимся в состоянии `Invalid`, и какое-то ядро запрашивает данные, то происходит `Processor Read` (PrRd). Затем он получает данные в свой кэш и выставляет эти данные как `Valid`.
|
||||
В какой-то момент это ядро видит, что какое-то ядро записало по этому адресу (то есть на шине произошла запись `Bus Write`), тогда оно сразу меняет состояние этой ячейки на `Invalid`, потому что в этот момент времени у него неактуальные данные.
|
||||
|
||||

|
||||
|
||||
*Рис. 31. Основные действия для данного протокола.
|
||||
*Рис. 31. Основные действия для данного протокола.*
|
||||
|
||||
Таким образом, если мы читаем данные, то мы переходим в состояние `Valid`.Если мы видим, что какое-то ядро записывает по этому адресу, то переходим в состояние `Invalid`.
|
||||
|
||||
@@ -480,17 +481,17 @@ Snoopy кэш отличается от обычного кэша наличие
|
||||
|
||||

|
||||
|
||||
*Рис. 32. Пример применения протокола `Valid/Invalid`.
|
||||
*Рис. 32. Пример применения протокола `Valid/Invalid`.*
|
||||
|
||||
1) Допустим, ядро 0 сначала загружаю по адресу `A`. На шине запрашивается чтение, в кэш попадает запись с состоянием `Valid`.
|
||||
2) Затем загружается второе ядро по адресу `A`, теперь там тоже запись `Valid`.
|
||||
3) Теперь происходит запись числа в память, кэш видит это и делает `Invalidate` данных (обнуляет их).
|
||||
4) Когда произойдёт очередной `load`, он увидит, что мы находимся в состоянии `Invalidate`.
|
||||
5) Теперь просто зачитаем обновленные данные.
|
||||
1) Допустим, ядро 0 сначала загружает по адресу `A` число 2. На шине запрашивается чтение, в кэш попадает запись с состоянием `Valid`.
|
||||
2) Затем загружает ядро 1 по адресу `A` число 2, теперь там тоже запись `Valid`.
|
||||
3) Теперь происходит запись числа 3 в память через ядро 0, кэш ядра 1 видит это и делает `Invalidate` данных (обнуляет их).
|
||||
4) Когда произойдёт очередной `load` на ядре 1, он увидит, что данные находятся в состоянии `Invalidate`.
|
||||
5) Теперь просто зачитаем обновленные данные из основной памяти.
|
||||
|
||||

|
||||
|
||||
*Рис. 33. Пример применения протокола `Valid/Invalid` с пояснениями.
|
||||
*Рис. 33. Пример применения протокола `Valid/Invalid` с пояснениями.*
|
||||
|
||||
Проблемы `VI`:
|
||||
|
||||
@@ -501,9 +502,9 @@ Snoopy кэш отличается от обычного кэша наличие
|
||||
|
||||
Каждая строка в каждом кэше поддерживает `MSI` состояния:
|
||||
|
||||
- `I`-кэш не содержит адреса;
|
||||
- `S`-кэш содержит адрес, но он так же может находится в других кэшах, следовательно он может быть только прочитан;
|
||||
- `M`-кэш содержит этот адрес, следовательно он может быть и прочитан и записан — любой другой кэш имевший этот адрес будет признан недействительным (то есть как только запишется по этому адресу все остальные аннулируют информацию об этом).
|
||||
- `I`- кэш не содержит адреса;
|
||||
- `S`- кэш содержит адрес, но он так же может находится в других кэшах, следовательно он может быть только прочитан;
|
||||
- `M`- только этот кэш содержит этот адрес, следовательно он может быть и прочитан и записан — любой другой кэш, имевший этот адрес, будет признан недействительным (то есть как только запишется по этому адресу, все остальные аннулируют информацию об этом).
|
||||
|
||||
### MSI протокол FSM
|
||||
|
||||
@@ -515,22 +516,22 @@ Snoopy кэш отличается от обычного кэша наличие
|
||||
|
||||

|
||||
|
||||
*Рис. 34. `MSI` протокол.
|
||||
*Рис. 34. `MSI` протокол.*
|
||||
|
||||

|
||||
|
||||
*Рис. 35. Основные действия для данного протокола.
|
||||
*Рис. 35. Основные действия для данного протокола.*
|
||||
|
||||
- Недостатки `VI`: каждая запись обновляет основную память, и каждая запись требует широковещательной передачи и слежки.
|
||||
- `MSI`: возможность реализации кэша с обратной записью (`writeback`) + удовлетворяет локальную запись.
|
||||
|
||||
### Оптимизация MSI: состояние E
|
||||
|
||||
Наблюдение: выполнение последовательной чтения-изменения-записи на частных данных является обычным делом.
|
||||
Наблюдение: выполнение последовательностей чтения-изменения-записи на частных данных является обычным делом.
|
||||
|
||||
В чём проблема `MSI`?
|
||||
|
||||
- Две данные транзакции для каждого чтения-изменения-записи частных данных.
|
||||
- Две шинные транзакции для каждого чтения-изменения-записи частных данных.
|
||||
|
||||
Решение: `Е-состояние` (`Exclusive`)
|
||||
|
||||
@@ -548,7 +549,7 @@ Snoopy кэш отличается от обычного кэша наличие
|
||||
|
||||

|
||||
|
||||
*Рис. 36. Протокол `MESI`: усовершенствованный.
|
||||
*Рис. 36. Протокол `MESI`: усовершенствованный.*
|
||||
|
||||
### Когерентность кэш и ложное совместное использование
|
||||
|
||||
@@ -556,15 +557,19 @@ Snoopy кэш отличается от обычного кэша наличие
|
||||
|
||||

|
||||
|
||||
*Рис. 37. Строка кэша.
|
||||
*Рис. 37. Строка кэша.*
|
||||
|
||||
Предположим `P₁` записывает `wordᵢ` и `P₂` записывает `wordₖ` и оба слова имеют один и тот же адрес строки.
|
||||
Что может произойти?
|
||||
|
||||
Из-за того что присутствуют алгоритмы когерентности, будет происходить *пинг-понг*.
|
||||
Из-за того, что присутствуют алгоритмы когерентности, будет происходить *пинг-понг*.
|
||||
Строка может быть недействительной (*пинг-понг*) много раз без необходимости, потому что адреса находятся в одной строке.
|
||||
|
||||
### Основные материалы лекции
|
||||
## Основные материалы лекции
|
||||
|
||||
1. [Ссылка](https://www.youtube.com/watch?v=wr7KuOSPP5I&list=PL0def37HEo5KHPjwK7A5bd4RJGg4djPVf&index=26) на видеозапись лекции
|
||||
2. [Ссылка](https://onedrive.live.com/?authkey=!AIXUSz0MyutL6hs&id=1FF28DEC684C2C56!81692&cid=1FF28DEC684C2C56) на лекцию в формате Power Point
|
||||
|
||||
## Дополнительные материалы к лекции для саморазвития
|
||||
|
||||
1. [Демонстрация протокола MESI](https://www.scss.tcd.ie/jeremy.jones/vivio/caches/MESIHelp.htm)
|
||||
|
Reference in New Issue
Block a user