OSTEP 34
This commit is contained in:
parent
083bb41b59
commit
11facbf2ef
@ -2836,5 +2836,73 @@
|
|||||||
:height 1209.6}),
|
:height 1209.6}),
|
||||||
:page 440},
|
:page 440},
|
||||||
:content {:text "implicit blocking "},
|
:content {:text "implicit blocking "},
|
||||||
|
:properties {:color "yellow"}}
|
||||||
|
{:id #uuid "6436ca1f-f4e7-431e-9620-be7764825acd",
|
||||||
|
:page 448,
|
||||||
|
:position {:bounding {:x1 457.33807373046875,
|
||||||
|
:y1 639.015625,
|
||||||
|
:x2 528.4306640625,
|
||||||
|
:y2 657.015625,
|
||||||
|
:width 864,
|
||||||
|
:height 1296},
|
||||||
|
:rects ({:x1 457.33807373046875,
|
||||||
|
:y1 639.015625,
|
||||||
|
:x2 528.4306640625,
|
||||||
|
:y2 657.015625,
|
||||||
|
:width 864,
|
||||||
|
:height 1296}),
|
||||||
|
:page 448},
|
||||||
|
:content {:text "obstinate "},
|
||||||
|
:properties {:color "green"}}
|
||||||
|
{:id #uuid "6436caa1-6fe0-4de8-9ad4-2a057960fc1a",
|
||||||
|
:page 448,
|
||||||
|
:position {:bounding {:x1 650.139892578125,
|
||||||
|
:y1 934.359375,
|
||||||
|
:x2 691.9168701171875,
|
||||||
|
:y2 952.359375,
|
||||||
|
:width 864,
|
||||||
|
:height 1296},
|
||||||
|
:rects ({:x1 650.139892578125,
|
||||||
|
:y1 934.359375,
|
||||||
|
:x2 691.9168701171875,
|
||||||
|
:y2 952.359375,
|
||||||
|
:width 864,
|
||||||
|
:height 1296}),
|
||||||
|
:page 448},
|
||||||
|
:content {:text "pickle"},
|
||||||
|
:properties {:color "green"}}
|
||||||
|
{:id #uuid "6436cb20-ee0b-4359-a39a-4178a4e8a4f7",
|
||||||
|
:page 448,
|
||||||
|
:position {:bounding {:x1 225.3008270263672,
|
||||||
|
:y1 1069.984375,
|
||||||
|
:x2 259.7266540527344,
|
||||||
|
:y2 1087.984375,
|
||||||
|
:width 864,
|
||||||
|
:height 1296},
|
||||||
|
:rects ({:x1 225.3008270263672,
|
||||||
|
:y1 1069.984375,
|
||||||
|
:x2 259.7266540527344,
|
||||||
|
:y2 1087.984375,
|
||||||
|
:width 864,
|
||||||
|
:height 1296}),
|
||||||
|
:page 448},
|
||||||
|
:content {:text "segue"},
|
||||||
|
:properties {:color "green"}}
|
||||||
|
{:id #uuid "6436cc2e-b1af-4555-9d1d-808e6de120b1",
|
||||||
|
:page 450,
|
||||||
|
:position {:bounding {:x1 116.09375,
|
||||||
|
:y1 713.578125,
|
||||||
|
:x2 311.3595275878906,
|
||||||
|
:y2 735.578125,
|
||||||
|
:width 864,
|
||||||
|
:height 1296},
|
||||||
|
:rects ({:x1 116.09375,
|
||||||
|
:y1 713.578125,
|
||||||
|
:x2 311.3595275878906,
|
||||||
|
:y2 735.578125,
|
||||||
|
:width 864,
|
||||||
|
:height 1296}),
|
||||||
|
:page 450},
|
||||||
|
:content {:text "System Architecture"},
|
||||||
:properties {:color "yellow"}}],
|
:properties {:color "yellow"}}],
|
||||||
:extra {:page 351}}
|
:extra {:page 450}}
|
||||||
|
|||||||
@ -34,6 +34,9 @@
|
|||||||
;; Enable showing the body of blocks when referencing them.
|
;; Enable showing the body of blocks when referencing them.
|
||||||
:ui/show-full-blocks? false
|
:ui/show-full-blocks? false
|
||||||
|
|
||||||
|
;; Expand block references automatically when zoom-in
|
||||||
|
:ui/auto-expand-block-refs? true
|
||||||
|
|
||||||
;; Enable Block timestamp
|
;; Enable Block timestamp
|
||||||
:feature/enable-block-timestamps? false
|
:feature/enable-block-timestamps? false
|
||||||
|
|
||||||
@ -127,7 +130,7 @@
|
|||||||
;; 2. ` ` empty space between keys represents key chords. eg: `t s` means press `t` followed by `s`
|
;; 2. ` ` empty space between keys represents key chords. eg: `t s` means press `t` followed by `s`
|
||||||
;; 3. `mod` means `Ctrl` for Windows/Linux and `Command` for Mac
|
;; 3. `mod` means `Ctrl` for Windows/Linux and `Command` for Mac
|
||||||
;; 4. use `false` to disable particular shortcut
|
;; 4. use `false` to disable particular shortcut
|
||||||
;; 4. you can define multiple bindings for one action, eg `["ctrl+j" "down"]`
|
;; 5. you can define multiple bindings for one action, eg `["ctrl+j" "down"]`
|
||||||
;; full list of configurable shortcuts are available below:
|
;; full list of configurable shortcuts are available below:
|
||||||
;; https://github.com/logseq/logseq/blob/master/src/main/frontend/modules/shortcut/config.cljs
|
;; https://github.com/logseq/logseq/blob/master/src/main/frontend/modules/shortcut/config.cljs
|
||||||
;; Example:
|
;; Example:
|
||||||
@ -135,7 +138,7 @@
|
|||||||
;; {:editor/new-block "enter"
|
;; {:editor/new-block "enter"
|
||||||
;; :editor/new-line "shift+enter"
|
;; :editor/new-line "shift+enter"
|
||||||
;; :editor/insert-link "mod+shift+k"
|
;; :editor/insert-link "mod+shift+k"
|
||||||
;; :editor/hightlight false
|
;; :editor/highlight false
|
||||||
;; :ui/toggle-settings "t s"
|
;; :ui/toggle-settings "t s"
|
||||||
;; :editor/up ["ctrl+k" "up"]
|
;; :editor/up ["ctrl+k" "up"]
|
||||||
;; :editor/down ["ctrl+j" "down"]
|
;; :editor/down ["ctrl+j" "down"]
|
||||||
@ -267,7 +270,7 @@
|
|||||||
;; :property/separated-by-commas #{}
|
;; :property/separated-by-commas #{}
|
||||||
|
|
||||||
;; Properties that are ignored when parsing property values for references
|
;; Properties that are ignored when parsing property values for references
|
||||||
;; :ignored-page-references-keywords #{"author" "startup"}
|
;; :ignored-page-references-keywords #{:author :startup}
|
||||||
|
|
||||||
;; logbook setup
|
;; logbook setup
|
||||||
;; :logbook/settings
|
;; :logbook/settings
|
||||||
@ -310,7 +313,7 @@
|
|||||||
;; :media "[[quick capture]] **{time}**: {url}"}
|
;; :media "[[quick capture]] **{time}**: {url}"}
|
||||||
|
|
||||||
;; Quick capture options
|
;; Quick capture options
|
||||||
;; :quick-capture-options {:insert-today? false :redirect-page? false :default-page nil}
|
;; :quick-capture-options {:insert-today? false :redirect-page? false :default-page "my page"}
|
||||||
|
|
||||||
;; File sync options
|
;; File sync options
|
||||||
;; Ignore these files when syncing, regexp is supported.
|
;; Ignore these files when syncing, regexp is supported.
|
||||||
@ -339,6 +342,7 @@
|
|||||||
;; ;use triple underscore `___` for slash `/` in page title
|
;; ;use triple underscore `___` for slash `/` in page title
|
||||||
;; ;use Percent-encoding for other invalid characters
|
;; ;use Percent-encoding for other invalid characters
|
||||||
:file/name-format :triple-lowbar
|
:file/name-format :triple-lowbar
|
||||||
|
:ui/show-brackets? false
|
||||||
|
|
||||||
;; specify the format of the filename for journal files
|
;; specify the format of the filename for journal files
|
||||||
;; :journal/file-name-format "yyyy_MM_dd"
|
;; :journal/file-name-format "yyyy_MM_dd"
|
||||||
@ -9,7 +9,7 @@
|
|||||||
;; Preferred workflow style.
|
;; Preferred workflow style.
|
||||||
;; Value is either ":now" for NOW/LATER style,
|
;; Value is either ":now" for NOW/LATER style,
|
||||||
;; or ":todo" for TODO/DOING style.
|
;; or ":todo" for TODO/DOING style.
|
||||||
:preferred-workflow :now
|
:preferred-workflow :todo
|
||||||
|
|
||||||
;; The app will ignore those directories or files.
|
;; The app will ignore those directories or files.
|
||||||
;; E.g. :hidden ["/archived" "/test.md" "../assets/archived"]
|
;; E.g. :hidden ["/archived" "/test.md" "../assets/archived"]
|
||||||
@ -35,7 +35,7 @@
|
|||||||
:ui/show-full-blocks? false
|
:ui/show-full-blocks? false
|
||||||
|
|
||||||
;; Expand block references automatically when zoom-in
|
;; Expand block references automatically when zoom-in
|
||||||
:ui/auto-expand-block-refs? true
|
:ui/auto-expand-block-refs? false
|
||||||
|
|
||||||
;; Enable Block timestamp
|
;; Enable Block timestamp
|
||||||
:feature/enable-block-timestamps? false
|
:feature/enable-block-timestamps? false
|
||||||
@ -342,6 +342,7 @@
|
|||||||
;; ;use triple underscore `___` for slash `/` in page title
|
;; ;use triple underscore `___` for slash `/` in page title
|
||||||
;; ;use Percent-encoding for other invalid characters
|
;; ;use Percent-encoding for other invalid characters
|
||||||
:file/name-format :triple-lowbar
|
:file/name-format :triple-lowbar
|
||||||
|
:ui/show-brackets? false
|
||||||
|
|
||||||
;; specify the format of the filename for journal files
|
;; specify the format of the filename for journal files
|
||||||
;; :journal/file-name-format "yyyy_MM_dd"
|
;; :journal/file-name-format "yyyy_MM_dd"
|
||||||
350
logseq/bak/logseq/config/2023-04-12T15_07_19.432Z.Desktop.edn
Normal file
350
logseq/bak/logseq/config/2023-04-12T15_07_19.432Z.Desktop.edn
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
{:meta/version 1
|
||||||
|
|
||||||
|
;; Currently, we support either "Markdown" or "Org".
|
||||||
|
;; This can overwrite your global preference so that
|
||||||
|
;; maybe your personal preferred format is Org but you'd
|
||||||
|
;; need to use Markdown for some projects.
|
||||||
|
;; :preferred-format ""
|
||||||
|
|
||||||
|
;; Preferred workflow style.
|
||||||
|
;; Value is either ":now" for NOW/LATER style,
|
||||||
|
;; or ":todo" for TODO/DOING style.
|
||||||
|
:preferred-workflow :todo
|
||||||
|
|
||||||
|
;; The app will ignore those directories or files.
|
||||||
|
;; E.g. :hidden ["/archived" "/test.md" "../assets/archived"]
|
||||||
|
:hidden []
|
||||||
|
|
||||||
|
;; When creating the new journal page, the app will use your template if there is one.
|
||||||
|
;; You only need to input your template name here.
|
||||||
|
:default-templates
|
||||||
|
{:journals ""}
|
||||||
|
|
||||||
|
;; Set a custom date format for journal page title
|
||||||
|
;; Example:
|
||||||
|
;; :journal/page-title-format "EEE, do MMM yyyy"
|
||||||
|
|
||||||
|
;; Whether to enable hover on tooltip preview feature
|
||||||
|
;; Default is true, you can also toggle this via setting page
|
||||||
|
:ui/enable-tooltip? true
|
||||||
|
|
||||||
|
;; Show brackets around page references
|
||||||
|
;; :ui/show-brackets? true
|
||||||
|
|
||||||
|
;; Enable showing the body of blocks when referencing them.
|
||||||
|
:ui/show-full-blocks? false
|
||||||
|
|
||||||
|
;; Expand block references automatically when zoom-in
|
||||||
|
:ui/auto-expand-block-refs? false
|
||||||
|
|
||||||
|
;; Enable Block timestamp
|
||||||
|
:feature/enable-block-timestamps? false
|
||||||
|
|
||||||
|
;; Enable remove accents when searching.
|
||||||
|
;; After toggle this option, please remember to rebuild your search index by press (cmd+c cmd+s).
|
||||||
|
:feature/enable-search-remove-accents? true
|
||||||
|
|
||||||
|
;; Enable journals
|
||||||
|
;; :feature/enable-journals? true
|
||||||
|
|
||||||
|
;; Enable flashcards
|
||||||
|
;; :feature/enable-flashcards? true
|
||||||
|
|
||||||
|
;; Enable Whiteboards
|
||||||
|
;; :feature/enable-whiteboards? true
|
||||||
|
|
||||||
|
;; Disable the built-in Scheduled tasks and deadlines query
|
||||||
|
;; :feature/disable-scheduled-and-deadline-query? true
|
||||||
|
|
||||||
|
;; Specify the number of days in the future to display in the
|
||||||
|
;; scheduled tasks and deadlines query, with a default value of 0 which
|
||||||
|
;; only displays tasks for today.
|
||||||
|
;; Example usage:
|
||||||
|
;; Display all scheduled tasks and deadlines in the next 7 days
|
||||||
|
;; :scheduled/future-days 7
|
||||||
|
|
||||||
|
;; Specify the date on which the week starts.
|
||||||
|
;; Goes from 0 to 6 (Monday to Sunday), default to 6
|
||||||
|
:start-of-week 6
|
||||||
|
|
||||||
|
;; Specify a custom CSS import
|
||||||
|
;; This option take precedence over your local `logseq/custom.css` file
|
||||||
|
;; You may find a list of awesome logseq themes here:
|
||||||
|
;; https://github.com/logseq/awesome-logseq#css-themes
|
||||||
|
;; Example:
|
||||||
|
;; :custom-css-url "@import url('https://cdn.jsdelivr.net/gh/dracula/logseq@master/custom.css');"
|
||||||
|
|
||||||
|
;; Specify a custom js import
|
||||||
|
;; This option take precedence over your local `logseq/custom.js` file
|
||||||
|
;; :custom-js-url ""
|
||||||
|
|
||||||
|
;; Set a custom Arweave gateway
|
||||||
|
;; Default gateway: https://arweave.net
|
||||||
|
;; :arweave/gateway ""
|
||||||
|
|
||||||
|
;; Set Bullet indentation when exporting
|
||||||
|
;; default option: tab
|
||||||
|
;; Possible options are for `:sidebar` are
|
||||||
|
;; 1. `:eight-spaces` as eight spaces
|
||||||
|
;; 2. `:four-spaces` as four spaces
|
||||||
|
;; 3. `:two-spaces` as two spaces
|
||||||
|
;; :export/bullet-indentation :tab
|
||||||
|
|
||||||
|
;; When :all-pages-public? true, export repo would export all pages within that repo.
|
||||||
|
;; Regardless of whether you've set any page to public or not.
|
||||||
|
;; Example:
|
||||||
|
;; :publishing/all-pages-public? true
|
||||||
|
|
||||||
|
;; Specify default home page and sidebar status for Logseq
|
||||||
|
;; If not specified, Logseq default opens journals page on startup
|
||||||
|
;; value for `:page` is name of page
|
||||||
|
;; Possible options for `:sidebar` are
|
||||||
|
;; 1. `"Contents"` to open up `Contents` in sidebar by default
|
||||||
|
;; 2. `page name` to open up some page in sidebar
|
||||||
|
;; 3. Or multiple pages in an array ["Contents" "Page A" "Page B"]
|
||||||
|
;; If `:sidebar` is not set, sidebar will be hidden
|
||||||
|
;; Example:
|
||||||
|
;; 1. Setup page "Changelog" as home page and "Contents" in sidebar
|
||||||
|
;; :default-home {:page "Changelog", :sidebar "Contents"}
|
||||||
|
;; 2. Setup page "Jun 3rd, 2021" as home page without sidebar
|
||||||
|
;; :default-home {:page "Jun 3rd, 2021"}
|
||||||
|
;; 3. Setup page "home" as home page with multiple pages in sidebar
|
||||||
|
;; :default-home {:page "home" :sidebar ["page a" "page b"]}
|
||||||
|
|
||||||
|
;; Tell logseq to use a specific folder in the repo as a default location for notes
|
||||||
|
;; if not specified, notes are stored in `pages` directory
|
||||||
|
;; :pages-directory "your-directory"
|
||||||
|
|
||||||
|
;; Tell logseq to use a specific folder in the repo as a default location for journals
|
||||||
|
;; if not specified, journals are stored in `journals` directory
|
||||||
|
;; :journals-directory "your-directory"
|
||||||
|
|
||||||
|
;; Set this to true will convert
|
||||||
|
;; `[[Grant Ideas]]` to `[[file:./grant_ideas.org][Grant Ideas]]` for org-mode
|
||||||
|
;; For more, see https://github.com/logseq/logseq/issues/672
|
||||||
|
;; :org-mode/insert-file-link? true
|
||||||
|
|
||||||
|
;; Setup custom shortcuts under `:shortcuts` key
|
||||||
|
;; Syntax:
|
||||||
|
;; 1. `+` means keys pressing simultaneously. eg: `ctrl+shift+a`
|
||||||
|
;; 2. ` ` empty space between keys represents key chords. eg: `t s` means press `t` followed by `s`
|
||||||
|
;; 3. `mod` means `Ctrl` for Windows/Linux and `Command` for Mac
|
||||||
|
;; 4. use `false` to disable particular shortcut
|
||||||
|
;; 5. you can define multiple bindings for one action, eg `["ctrl+j" "down"]`
|
||||||
|
;; full list of configurable shortcuts are available below:
|
||||||
|
;; https://github.com/logseq/logseq/blob/master/src/main/frontend/modules/shortcut/config.cljs
|
||||||
|
;; Example:
|
||||||
|
;; :shortcuts
|
||||||
|
;; {:editor/new-block "enter"
|
||||||
|
;; :editor/new-line "shift+enter"
|
||||||
|
;; :editor/insert-link "mod+shift+k"
|
||||||
|
;; :editor/highlight false
|
||||||
|
;; :ui/toggle-settings "t s"
|
||||||
|
;; :editor/up ["ctrl+k" "up"]
|
||||||
|
;; :editor/down ["ctrl+j" "down"]
|
||||||
|
;; :editor/left ["ctrl+h" "left"]
|
||||||
|
;; :editor/right ["ctrl+l" "right"]}
|
||||||
|
:shortcuts {}
|
||||||
|
|
||||||
|
;; By default, pressing `Enter` in the document mode will create a new line.
|
||||||
|
;; Set this to `true` so that it's the same behaviour as the usual outliner mode.
|
||||||
|
:shortcut/doc-mode-enter-for-new-block? false
|
||||||
|
|
||||||
|
;; Block content larger than `block/content-max-length` will not be searchable
|
||||||
|
;; or editable for performance.
|
||||||
|
:block/content-max-length 10000
|
||||||
|
|
||||||
|
;; Whether to show command doc on hover
|
||||||
|
:ui/show-command-doc? true
|
||||||
|
|
||||||
|
;; Whether to show empty bullets for non-document mode (the default mode)
|
||||||
|
:ui/show-empty-bullets? false
|
||||||
|
|
||||||
|
;; Pre-defined :view function to use with advanced queries
|
||||||
|
:query/views
|
||||||
|
{:pprint
|
||||||
|
(fn [r] [:pre.code (pprint r)])}
|
||||||
|
|
||||||
|
;; Pre-defined :result-transform function for use with advanced queries
|
||||||
|
:query/result-transforms
|
||||||
|
{:sort-by-priority
|
||||||
|
(fn [result] (sort-by (fn [h] (get h :block/priority "Z")) result))}
|
||||||
|
|
||||||
|
;; The app will show those queries in today's journal page,
|
||||||
|
;; the "NOW" query asks the tasks which need to be finished "now",
|
||||||
|
;; the "NEXT" query asks the future tasks.
|
||||||
|
:default-queries
|
||||||
|
{:journals
|
||||||
|
[{:title "🔨 NOW"
|
||||||
|
:query [:find (pull ?h [*])
|
||||||
|
:in $ ?start ?today
|
||||||
|
:where
|
||||||
|
[?h :block/marker ?marker]
|
||||||
|
[(contains? #{"NOW" "DOING"} ?marker)]
|
||||||
|
[?h :block/page ?p]
|
||||||
|
[?p :block/journal? true]
|
||||||
|
[?p :block/journal-day ?d]
|
||||||
|
[(>= ?d ?start)]
|
||||||
|
[(<= ?d ?today)]]
|
||||||
|
:inputs [:14d :today]
|
||||||
|
:result-transform (fn [result]
|
||||||
|
(sort-by (fn [h]
|
||||||
|
(get h :block/priority "Z")) result))
|
||||||
|
:collapsed? false}
|
||||||
|
{:title "📅 NEXT"
|
||||||
|
:query [:find (pull ?h [*])
|
||||||
|
:in $ ?start ?next
|
||||||
|
:where
|
||||||
|
[?h :block/marker ?marker]
|
||||||
|
[(contains? #{"NOW" "LATER" "TODO"} ?marker)]
|
||||||
|
[?h :block/page ?p]
|
||||||
|
[?p :block/journal? true]
|
||||||
|
[?p :block/journal-day ?d]
|
||||||
|
[(> ?d ?start)]
|
||||||
|
[(< ?d ?next)]]
|
||||||
|
:inputs [:today :7d-after]
|
||||||
|
:collapsed? false}]}
|
||||||
|
|
||||||
|
;; Add your own commands to slash menu to speedup.
|
||||||
|
;; E.g.
|
||||||
|
;; :commands
|
||||||
|
;; [
|
||||||
|
;; ["js" "Javascript"]
|
||||||
|
;; ["md" "Markdown"]
|
||||||
|
;; ]
|
||||||
|
:commands
|
||||||
|
[]
|
||||||
|
|
||||||
|
;; By default, a block can only be collapsed if it has some children.
|
||||||
|
;; `:outliner/block-title-collapse-enabled? true` enables a block with a title
|
||||||
|
;; (multiple lines) can be collapsed too. For example:
|
||||||
|
;; - block title
|
||||||
|
;; block content
|
||||||
|
:outliner/block-title-collapse-enabled? false
|
||||||
|
|
||||||
|
;; Macros replace texts and will make you more productive.
|
||||||
|
;; For example:
|
||||||
|
;; Change the :macros value below to:
|
||||||
|
;; {"poem" "Rose is $1, violet's $2. Life's ordered: Org assists you."}
|
||||||
|
;; input "{{poem red,blue}}"
|
||||||
|
;; becomes
|
||||||
|
;; Rose is red, violet's blue. Life's ordered: Org assists you.
|
||||||
|
:macros {}
|
||||||
|
|
||||||
|
;; The default level to be opened for the linked references.
|
||||||
|
;; For example, if we have some example blocks like this:
|
||||||
|
;; - a [[page]] (level 1)
|
||||||
|
;; - b (level 2)
|
||||||
|
;; - c (level 3)
|
||||||
|
;; - d (level 4)
|
||||||
|
;;
|
||||||
|
;; With the default value of level 2, `b` will be collapsed.
|
||||||
|
;; If we set the level's value to 3, `b` will be opened and `c` will be collapsed.
|
||||||
|
:ref/default-open-blocks-level 2
|
||||||
|
|
||||||
|
:ref/linked-references-collapsed-threshold 50
|
||||||
|
|
||||||
|
;; Favorites to list on the left sidebar
|
||||||
|
:favorites []
|
||||||
|
|
||||||
|
;; any number between 0 and 1 (the greater it is the faster the changes of the next-interval of card reviews) (default 0.5)
|
||||||
|
;; :srs/learning-fraction 0.5
|
||||||
|
|
||||||
|
;; the initial interval after the first successful review of a card (default 4)
|
||||||
|
;; :srs/initial-interval 4
|
||||||
|
|
||||||
|
;; hide specific properties for blocks
|
||||||
|
;; E.g. :block-hidden-properties #{:created-at :updated-at}
|
||||||
|
;; :block-hidden-properties #{}
|
||||||
|
|
||||||
|
;; Enable all your properties to have corresponding pages
|
||||||
|
:property-pages/enabled? true
|
||||||
|
|
||||||
|
;; Properties to exclude from having property pages
|
||||||
|
;; E.g.:property-pages/excludelist #{:duration :author}
|
||||||
|
;; :property-pages/excludelist
|
||||||
|
|
||||||
|
;; By default, property value separated by commas will not be treated as
|
||||||
|
;; page references. You can add properties to enable it.
|
||||||
|
;; E.g. :property/separated-by-commas #{:alias :tags}
|
||||||
|
;; :property/separated-by-commas #{}
|
||||||
|
|
||||||
|
;; Properties that are ignored when parsing property values for references
|
||||||
|
;; :ignored-page-references-keywords #{:author :startup}
|
||||||
|
|
||||||
|
;; logbook setup
|
||||||
|
;; :logbook/settings
|
||||||
|
;; {:with-second-support? false ;limit logbook to minutes, seconds will be eliminated
|
||||||
|
;; :enabled-in-all-blocks true ;display logbook in all blocks after timetracking
|
||||||
|
;; :enabled-in-timestamped-blocks false ;don't display logbook at all
|
||||||
|
;; }
|
||||||
|
|
||||||
|
;; Mobile photo uploading setup
|
||||||
|
;; :mobile/photo
|
||||||
|
;; {:allow-editing? true
|
||||||
|
;; :quality 80}
|
||||||
|
|
||||||
|
;; Mobile features options
|
||||||
|
;; Gestures
|
||||||
|
;; :mobile
|
||||||
|
;; {:gestures/disabled-in-block-with-tags ["kanban"]}
|
||||||
|
|
||||||
|
;; Extra CodeMirror options
|
||||||
|
;; See https://codemirror.net/5/doc/manual.html#config for possible options
|
||||||
|
;; :editor/extra-codemirror-options {:keyMap "emacs" :lineWrapping true}
|
||||||
|
|
||||||
|
;; Enable logical outdenting
|
||||||
|
;; :editor/logical-outdenting? true
|
||||||
|
|
||||||
|
;; When both text and a file are in the clipboard, paste the file
|
||||||
|
;; :editor/preferred-pasting-file? true
|
||||||
|
|
||||||
|
;; Quick capture templates for receiving contents from other apps.
|
||||||
|
;; Each template contains three elements {time}, {text} and {url}, which can be auto-expanded
|
||||||
|
;; by received contents from other apps. Note: the {} cannot be omitted.
|
||||||
|
;; - {time}: capture time
|
||||||
|
;; - {date}: capture date using current date format, use `[[{date}]]` to get a page reference
|
||||||
|
;; - {text}: text that users selected before sharing.
|
||||||
|
;; - {url}: url or assets path for media files stored in Logseq.
|
||||||
|
;; You can also reorder them, or even only use one or two of them in the template.
|
||||||
|
;; You can also insert or format any text in the template as shown in the following examples.
|
||||||
|
;; :quick-capture-templates
|
||||||
|
;; {:text "[[quick capture]] **{time}**: {text} from {url}"
|
||||||
|
;; :media "[[quick capture]] **{time}**: {url}"}
|
||||||
|
|
||||||
|
;; Quick capture options
|
||||||
|
;; :quick-capture-options {:insert-today? false :redirect-page? false :default-page "my page"}
|
||||||
|
|
||||||
|
;; File sync options
|
||||||
|
;; Ignore these files when syncing, regexp is supported.
|
||||||
|
;; :file-sync/ignore-files []
|
||||||
|
|
||||||
|
;; dwim (do what I mean) for Enter key when editing.
|
||||||
|
;; Context-awareness of Enter key makes editing more easily
|
||||||
|
; :dwim/settings {
|
||||||
|
; :admonition&src? true
|
||||||
|
; :markup? false
|
||||||
|
; :block-ref? true
|
||||||
|
; :page-ref? true
|
||||||
|
; :properties? true
|
||||||
|
; :list? true
|
||||||
|
; }
|
||||||
|
|
||||||
|
;; Decide the way to escape the special characters in the page title.
|
||||||
|
;; Warning:
|
||||||
|
;; This is a dangerous operation. If you want to change the setting,
|
||||||
|
;; should access the setting `Filename format` and follow the instructions.
|
||||||
|
;; Or you have to rename all the affected files manually then re-index on all
|
||||||
|
;; clients after the files are synced. Wrong handling may cause page titles
|
||||||
|
;; containing special characters to be messy.
|
||||||
|
;; Available values:
|
||||||
|
;; :file/name-format :triple-lowbar
|
||||||
|
;; ;use triple underscore `___` for slash `/` in page title
|
||||||
|
;; ;use Percent-encoding for other invalid characters
|
||||||
|
:file/name-format :triple-lowbar
|
||||||
|
:ui/show-brackets? true
|
||||||
|
|
||||||
|
;; specify the format of the filename for journal files
|
||||||
|
;; :journal/file-name-format "yyyy_MM_dd"
|
||||||
|
|
||||||
|
}
|
||||||
350
logseq/bak/logseq/config/2023-04-12T15_07_28.101Z.Desktop.edn
Normal file
350
logseq/bak/logseq/config/2023-04-12T15_07_28.101Z.Desktop.edn
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
{:meta/version 1
|
||||||
|
|
||||||
|
;; Currently, we support either "Markdown" or "Org".
|
||||||
|
;; This can overwrite your global preference so that
|
||||||
|
;; maybe your personal preferred format is Org but you'd
|
||||||
|
;; need to use Markdown for some projects.
|
||||||
|
;; :preferred-format ""
|
||||||
|
|
||||||
|
;; Preferred workflow style.
|
||||||
|
;; Value is either ":now" for NOW/LATER style,
|
||||||
|
;; or ":todo" for TODO/DOING style.
|
||||||
|
:preferred-workflow :todo
|
||||||
|
|
||||||
|
;; The app will ignore those directories or files.
|
||||||
|
;; E.g. :hidden ["/archived" "/test.md" "../assets/archived"]
|
||||||
|
:hidden []
|
||||||
|
|
||||||
|
;; When creating the new journal page, the app will use your template if there is one.
|
||||||
|
;; You only need to input your template name here.
|
||||||
|
:default-templates
|
||||||
|
{:journals ""}
|
||||||
|
|
||||||
|
;; Set a custom date format for journal page title
|
||||||
|
;; Example:
|
||||||
|
;; :journal/page-title-format "EEE, do MMM yyyy"
|
||||||
|
|
||||||
|
;; Whether to enable hover on tooltip preview feature
|
||||||
|
;; Default is true, you can also toggle this via setting page
|
||||||
|
:ui/enable-tooltip? true
|
||||||
|
|
||||||
|
;; Show brackets around page references
|
||||||
|
;; :ui/show-brackets? true
|
||||||
|
|
||||||
|
;; Enable showing the body of blocks when referencing them.
|
||||||
|
:ui/show-full-blocks? false
|
||||||
|
|
||||||
|
;; Expand block references automatically when zoom-in
|
||||||
|
:ui/auto-expand-block-refs? false
|
||||||
|
|
||||||
|
;; Enable Block timestamp
|
||||||
|
:feature/enable-block-timestamps? false
|
||||||
|
|
||||||
|
;; Enable remove accents when searching.
|
||||||
|
;; After toggle this option, please remember to rebuild your search index by press (cmd+c cmd+s).
|
||||||
|
:feature/enable-search-remove-accents? true
|
||||||
|
|
||||||
|
;; Enable journals
|
||||||
|
;; :feature/enable-journals? true
|
||||||
|
|
||||||
|
;; Enable flashcards
|
||||||
|
;; :feature/enable-flashcards? true
|
||||||
|
|
||||||
|
;; Enable Whiteboards
|
||||||
|
;; :feature/enable-whiteboards? true
|
||||||
|
|
||||||
|
;; Disable the built-in Scheduled tasks and deadlines query
|
||||||
|
;; :feature/disable-scheduled-and-deadline-query? true
|
||||||
|
|
||||||
|
;; Specify the number of days in the future to display in the
|
||||||
|
;; scheduled tasks and deadlines query, with a default value of 0 which
|
||||||
|
;; only displays tasks for today.
|
||||||
|
;; Example usage:
|
||||||
|
;; Display all scheduled tasks and deadlines in the next 7 days
|
||||||
|
;; :scheduled/future-days 7
|
||||||
|
|
||||||
|
;; Specify the date on which the week starts.
|
||||||
|
;; Goes from 0 to 6 (Monday to Sunday), default to 6
|
||||||
|
:start-of-week 6
|
||||||
|
|
||||||
|
;; Specify a custom CSS import
|
||||||
|
;; This option take precedence over your local `logseq/custom.css` file
|
||||||
|
;; You may find a list of awesome logseq themes here:
|
||||||
|
;; https://github.com/logseq/awesome-logseq#css-themes
|
||||||
|
;; Example:
|
||||||
|
;; :custom-css-url "@import url('https://cdn.jsdelivr.net/gh/dracula/logseq@master/custom.css');"
|
||||||
|
|
||||||
|
;; Specify a custom js import
|
||||||
|
;; This option take precedence over your local `logseq/custom.js` file
|
||||||
|
;; :custom-js-url ""
|
||||||
|
|
||||||
|
;; Set a custom Arweave gateway
|
||||||
|
;; Default gateway: https://arweave.net
|
||||||
|
;; :arweave/gateway ""
|
||||||
|
|
||||||
|
;; Set Bullet indentation when exporting
|
||||||
|
;; default option: tab
|
||||||
|
;; Possible options are for `:sidebar` are
|
||||||
|
;; 1. `:eight-spaces` as eight spaces
|
||||||
|
;; 2. `:four-spaces` as four spaces
|
||||||
|
;; 3. `:two-spaces` as two spaces
|
||||||
|
;; :export/bullet-indentation :tab
|
||||||
|
|
||||||
|
;; When :all-pages-public? true, export repo would export all pages within that repo.
|
||||||
|
;; Regardless of whether you've set any page to public or not.
|
||||||
|
;; Example:
|
||||||
|
;; :publishing/all-pages-public? true
|
||||||
|
|
||||||
|
;; Specify default home page and sidebar status for Logseq
|
||||||
|
;; If not specified, Logseq default opens journals page on startup
|
||||||
|
;; value for `:page` is name of page
|
||||||
|
;; Possible options for `:sidebar` are
|
||||||
|
;; 1. `"Contents"` to open up `Contents` in sidebar by default
|
||||||
|
;; 2. `page name` to open up some page in sidebar
|
||||||
|
;; 3. Or multiple pages in an array ["Contents" "Page A" "Page B"]
|
||||||
|
;; If `:sidebar` is not set, sidebar will be hidden
|
||||||
|
;; Example:
|
||||||
|
;; 1. Setup page "Changelog" as home page and "Contents" in sidebar
|
||||||
|
;; :default-home {:page "Changelog", :sidebar "Contents"}
|
||||||
|
;; 2. Setup page "Jun 3rd, 2021" as home page without sidebar
|
||||||
|
;; :default-home {:page "Jun 3rd, 2021"}
|
||||||
|
;; 3. Setup page "home" as home page with multiple pages in sidebar
|
||||||
|
;; :default-home {:page "home" :sidebar ["page a" "page b"]}
|
||||||
|
|
||||||
|
;; Tell logseq to use a specific folder in the repo as a default location for notes
|
||||||
|
;; if not specified, notes are stored in `pages` directory
|
||||||
|
;; :pages-directory "your-directory"
|
||||||
|
|
||||||
|
;; Tell logseq to use a specific folder in the repo as a default location for journals
|
||||||
|
;; if not specified, journals are stored in `journals` directory
|
||||||
|
;; :journals-directory "your-directory"
|
||||||
|
|
||||||
|
;; Set this to true will convert
|
||||||
|
;; `[[Grant Ideas]]` to `[[file:./grant_ideas.org][Grant Ideas]]` for org-mode
|
||||||
|
;; For more, see https://github.com/logseq/logseq/issues/672
|
||||||
|
;; :org-mode/insert-file-link? true
|
||||||
|
|
||||||
|
;; Setup custom shortcuts under `:shortcuts` key
|
||||||
|
;; Syntax:
|
||||||
|
;; 1. `+` means keys pressing simultaneously. eg: `ctrl+shift+a`
|
||||||
|
;; 2. ` ` empty space between keys represents key chords. eg: `t s` means press `t` followed by `s`
|
||||||
|
;; 3. `mod` means `Ctrl` for Windows/Linux and `Command` for Mac
|
||||||
|
;; 4. use `false` to disable particular shortcut
|
||||||
|
;; 5. you can define multiple bindings for one action, eg `["ctrl+j" "down"]`
|
||||||
|
;; full list of configurable shortcuts are available below:
|
||||||
|
;; https://github.com/logseq/logseq/blob/master/src/main/frontend/modules/shortcut/config.cljs
|
||||||
|
;; Example:
|
||||||
|
;; :shortcuts
|
||||||
|
;; {:editor/new-block "enter"
|
||||||
|
;; :editor/new-line "shift+enter"
|
||||||
|
;; :editor/insert-link "mod+shift+k"
|
||||||
|
;; :editor/highlight false
|
||||||
|
;; :ui/toggle-settings "t s"
|
||||||
|
;; :editor/up ["ctrl+k" "up"]
|
||||||
|
;; :editor/down ["ctrl+j" "down"]
|
||||||
|
;; :editor/left ["ctrl+h" "left"]
|
||||||
|
;; :editor/right ["ctrl+l" "right"]}
|
||||||
|
:shortcuts {}
|
||||||
|
|
||||||
|
;; By default, pressing `Enter` in the document mode will create a new line.
|
||||||
|
;; Set this to `true` so that it's the same behaviour as the usual outliner mode.
|
||||||
|
:shortcut/doc-mode-enter-for-new-block? false
|
||||||
|
|
||||||
|
;; Block content larger than `block/content-max-length` will not be searchable
|
||||||
|
;; or editable for performance.
|
||||||
|
:block/content-max-length 10000
|
||||||
|
|
||||||
|
;; Whether to show command doc on hover
|
||||||
|
:ui/show-command-doc? true
|
||||||
|
|
||||||
|
;; Whether to show empty bullets for non-document mode (the default mode)
|
||||||
|
:ui/show-empty-bullets? false
|
||||||
|
|
||||||
|
;; Pre-defined :view function to use with advanced queries
|
||||||
|
:query/views
|
||||||
|
{:pprint
|
||||||
|
(fn [r] [:pre.code (pprint r)])}
|
||||||
|
|
||||||
|
;; Pre-defined :result-transform function for use with advanced queries
|
||||||
|
:query/result-transforms
|
||||||
|
{:sort-by-priority
|
||||||
|
(fn [result] (sort-by (fn [h] (get h :block/priority "Z")) result))}
|
||||||
|
|
||||||
|
;; The app will show those queries in today's journal page,
|
||||||
|
;; the "NOW" query asks the tasks which need to be finished "now",
|
||||||
|
;; the "NEXT" query asks the future tasks.
|
||||||
|
:default-queries
|
||||||
|
{:journals
|
||||||
|
[{:title "🔨 NOW"
|
||||||
|
:query [:find (pull ?h [*])
|
||||||
|
:in $ ?start ?today
|
||||||
|
:where
|
||||||
|
[?h :block/marker ?marker]
|
||||||
|
[(contains? #{"NOW" "DOING"} ?marker)]
|
||||||
|
[?h :block/page ?p]
|
||||||
|
[?p :block/journal? true]
|
||||||
|
[?p :block/journal-day ?d]
|
||||||
|
[(>= ?d ?start)]
|
||||||
|
[(<= ?d ?today)]]
|
||||||
|
:inputs [:14d :today]
|
||||||
|
:result-transform (fn [result]
|
||||||
|
(sort-by (fn [h]
|
||||||
|
(get h :block/priority "Z")) result))
|
||||||
|
:collapsed? false}
|
||||||
|
{:title "📅 NEXT"
|
||||||
|
:query [:find (pull ?h [*])
|
||||||
|
:in $ ?start ?next
|
||||||
|
:where
|
||||||
|
[?h :block/marker ?marker]
|
||||||
|
[(contains? #{"NOW" "LATER" "TODO"} ?marker)]
|
||||||
|
[?h :block/page ?p]
|
||||||
|
[?p :block/journal? true]
|
||||||
|
[?p :block/journal-day ?d]
|
||||||
|
[(> ?d ?start)]
|
||||||
|
[(< ?d ?next)]]
|
||||||
|
:inputs [:today :7d-after]
|
||||||
|
:collapsed? false}]}
|
||||||
|
|
||||||
|
;; Add your own commands to slash menu to speedup.
|
||||||
|
;; E.g.
|
||||||
|
;; :commands
|
||||||
|
;; [
|
||||||
|
;; ["js" "Javascript"]
|
||||||
|
;; ["md" "Markdown"]
|
||||||
|
;; ]
|
||||||
|
:commands
|
||||||
|
[]
|
||||||
|
|
||||||
|
;; By default, a block can only be collapsed if it has some children.
|
||||||
|
;; `:outliner/block-title-collapse-enabled? true` enables a block with a title
|
||||||
|
;; (multiple lines) can be collapsed too. For example:
|
||||||
|
;; - block title
|
||||||
|
;; block content
|
||||||
|
:outliner/block-title-collapse-enabled? false
|
||||||
|
|
||||||
|
;; Macros replace texts and will make you more productive.
|
||||||
|
;; For example:
|
||||||
|
;; Change the :macros value below to:
|
||||||
|
;; {"poem" "Rose is $1, violet's $2. Life's ordered: Org assists you."}
|
||||||
|
;; input "{{poem red,blue}}"
|
||||||
|
;; becomes
|
||||||
|
;; Rose is red, violet's blue. Life's ordered: Org assists you.
|
||||||
|
:macros {}
|
||||||
|
|
||||||
|
;; The default level to be opened for the linked references.
|
||||||
|
;; For example, if we have some example blocks like this:
|
||||||
|
;; - a [[page]] (level 1)
|
||||||
|
;; - b (level 2)
|
||||||
|
;; - c (level 3)
|
||||||
|
;; - d (level 4)
|
||||||
|
;;
|
||||||
|
;; With the default value of level 2, `b` will be collapsed.
|
||||||
|
;; If we set the level's value to 3, `b` will be opened and `c` will be collapsed.
|
||||||
|
:ref/default-open-blocks-level 2
|
||||||
|
|
||||||
|
:ref/linked-references-collapsed-threshold 50
|
||||||
|
|
||||||
|
;; Favorites to list on the left sidebar
|
||||||
|
:favorites []
|
||||||
|
|
||||||
|
;; any number between 0 and 1 (the greater it is the faster the changes of the next-interval of card reviews) (default 0.5)
|
||||||
|
;; :srs/learning-fraction 0.5
|
||||||
|
|
||||||
|
;; the initial interval after the first successful review of a card (default 4)
|
||||||
|
;; :srs/initial-interval 4
|
||||||
|
|
||||||
|
;; hide specific properties for blocks
|
||||||
|
;; E.g. :block-hidden-properties #{:created-at :updated-at}
|
||||||
|
;; :block-hidden-properties #{}
|
||||||
|
|
||||||
|
;; Enable all your properties to have corresponding pages
|
||||||
|
:property-pages/enabled? true
|
||||||
|
|
||||||
|
;; Properties to exclude from having property pages
|
||||||
|
;; E.g.:property-pages/excludelist #{:duration :author}
|
||||||
|
;; :property-pages/excludelist
|
||||||
|
|
||||||
|
;; By default, property value separated by commas will not be treated as
|
||||||
|
;; page references. You can add properties to enable it.
|
||||||
|
;; E.g. :property/separated-by-commas #{:alias :tags}
|
||||||
|
;; :property/separated-by-commas #{}
|
||||||
|
|
||||||
|
;; Properties that are ignored when parsing property values for references
|
||||||
|
;; :ignored-page-references-keywords #{:author :startup}
|
||||||
|
|
||||||
|
;; logbook setup
|
||||||
|
;; :logbook/settings
|
||||||
|
;; {:with-second-support? false ;limit logbook to minutes, seconds will be eliminated
|
||||||
|
;; :enabled-in-all-blocks true ;display logbook in all blocks after timetracking
|
||||||
|
;; :enabled-in-timestamped-blocks false ;don't display logbook at all
|
||||||
|
;; }
|
||||||
|
|
||||||
|
;; Mobile photo uploading setup
|
||||||
|
;; :mobile/photo
|
||||||
|
;; {:allow-editing? true
|
||||||
|
;; :quality 80}
|
||||||
|
|
||||||
|
;; Mobile features options
|
||||||
|
;; Gestures
|
||||||
|
;; :mobile
|
||||||
|
;; {:gestures/disabled-in-block-with-tags ["kanban"]}
|
||||||
|
|
||||||
|
;; Extra CodeMirror options
|
||||||
|
;; See https://codemirror.net/5/doc/manual.html#config for possible options
|
||||||
|
;; :editor/extra-codemirror-options {:keyMap "emacs" :lineWrapping true}
|
||||||
|
|
||||||
|
;; Enable logical outdenting
|
||||||
|
;; :editor/logical-outdenting? true
|
||||||
|
|
||||||
|
;; When both text and a file are in the clipboard, paste the file
|
||||||
|
;; :editor/preferred-pasting-file? true
|
||||||
|
|
||||||
|
;; Quick capture templates for receiving contents from other apps.
|
||||||
|
;; Each template contains three elements {time}, {text} and {url}, which can be auto-expanded
|
||||||
|
;; by received contents from other apps. Note: the {} cannot be omitted.
|
||||||
|
;; - {time}: capture time
|
||||||
|
;; - {date}: capture date using current date format, use `[[{date}]]` to get a page reference
|
||||||
|
;; - {text}: text that users selected before sharing.
|
||||||
|
;; - {url}: url or assets path for media files stored in Logseq.
|
||||||
|
;; You can also reorder them, or even only use one or two of them in the template.
|
||||||
|
;; You can also insert or format any text in the template as shown in the following examples.
|
||||||
|
;; :quick-capture-templates
|
||||||
|
;; {:text "[[quick capture]] **{time}**: {text} from {url}"
|
||||||
|
;; :media "[[quick capture]] **{time}**: {url}"}
|
||||||
|
|
||||||
|
;; Quick capture options
|
||||||
|
;; :quick-capture-options {:insert-today? false :redirect-page? false :default-page "my page"}
|
||||||
|
|
||||||
|
;; File sync options
|
||||||
|
;; Ignore these files when syncing, regexp is supported.
|
||||||
|
;; :file-sync/ignore-files []
|
||||||
|
|
||||||
|
;; dwim (do what I mean) for Enter key when editing.
|
||||||
|
;; Context-awareness of Enter key makes editing more easily
|
||||||
|
; :dwim/settings {
|
||||||
|
; :admonition&src? true
|
||||||
|
; :markup? false
|
||||||
|
; :block-ref? true
|
||||||
|
; :page-ref? true
|
||||||
|
; :properties? true
|
||||||
|
; :list? true
|
||||||
|
; }
|
||||||
|
|
||||||
|
;; Decide the way to escape the special characters in the page title.
|
||||||
|
;; Warning:
|
||||||
|
;; This is a dangerous operation. If you want to change the setting,
|
||||||
|
;; should access the setting `Filename format` and follow the instructions.
|
||||||
|
;; Or you have to rename all the affected files manually then re-index on all
|
||||||
|
;; clients after the files are synced. Wrong handling may cause page titles
|
||||||
|
;; containing special characters to be messy.
|
||||||
|
;; Available values:
|
||||||
|
;; :file/name-format :triple-lowbar
|
||||||
|
;; ;use triple underscore `___` for slash `/` in page title
|
||||||
|
;; ;use Percent-encoding for other invalid characters
|
||||||
|
:file/name-format :triple-lowbar
|
||||||
|
:ui/show-brackets? false
|
||||||
|
|
||||||
|
;; specify the format of the filename for journal files
|
||||||
|
;; :journal/file-name-format "yyyy_MM_dd"
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,773 @@
|
|||||||
|
file:: [ostep_1681115599584_0.pdf](../assets/ostep_1681115599584_0.pdf)
|
||||||
|
file-path:: ../assets/ostep_1681115599584_0.pdf
|
||||||
|
|
||||||
|
- # Part II
|
||||||
|
- thread
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 311
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6433ca28-1bdf-433d-8ed9-0d54bf5ba940
|
||||||
|
collapsed:: true
|
||||||
|
- share the same address space and thus can access the same data
|
||||||
|
- context switch: the address space remains the same
|
||||||
|
hl-page:: 311
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6433cb70-d168-4863-8268-1e969df6ce06
|
||||||
|
hl-color:: yellow
|
||||||
|
- thread control blocks
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 311
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6433cb56-fbef-46da-83c2-13fa2dba2967
|
||||||
|
- thread-local storage: one stack per thread in the address space
|
||||||
|
hl-page:: 312
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6433cba2-61bd-4549-a29f-2ad85b3e30cd
|
||||||
|
hl-color:: yellow
|
||||||
|
- Why thread?
|
||||||
|
- possible speedup through parallelization
|
||||||
|
- enable overlap of IO in a single program
|
||||||
|
- Though these could be done through multi-processing, threading makes share data easier
|
||||||
|
- KEY CONCURRENCY TERMS
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 323
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6433eabf-48d6-4776-b66f-a5f7804d1ddc
|
||||||
|
collapsed:: true
|
||||||
|
- **indeterminate**: the results depend on the timing execution of the code.
|
||||||
|
- race condition
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 320
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6433e4cc-69e4-4057-8cc6-1766240d82f4
|
||||||
|
- A **critical section** is a piece of code that accesses a shared variable (or resource) and must not be concurrently executed by more than one thread.
|
||||||
|
hl-page:: 320
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6433e52b-1f38-4f7c-b168-0aed624f9bdf
|
||||||
|
hl-color:: yellow
|
||||||
|
- **mutual exclusion**: This property guarantees that if one thread is executing within the *critical section*, the others will be prevented from doing so.
|
||||||
|
hl-page:: 320
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6433e566-e6ef-45b3-84b1-eba981be914a
|
||||||
|
hl-color:: yellow
|
||||||
|
- Atomicity: *as a unit*, or, *all or none*
|
||||||
|
hl-page:: 321
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6433e6a1-407c-4936-b184-dee868ef4107
|
||||||
|
hl-color:: yellow
|
||||||
|
- synchronization primitives
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 322
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6433e729-7043-453b-8d60-6e6c41560543
|
||||||
|
- sane 精神健全的;神志正常的;明智的;理智的
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 322
|
||||||
|
hl-color:: green
|
||||||
|
id:: 6433e6e7-d995-4b69-96b3-261b79f94c1d
|
||||||
|
- Thread API
|
||||||
|
hl-page:: 327
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6433f35b-403b-4b25-b9f9-076e9e34777e
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
|
- `pthread_create` `pthread_join` `pthread_mutex_lock` `pthread_cond_*`
|
||||||
|
- Locks
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 339
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6433f45b-0345-4790-8379-3d1a94e57ef5
|
||||||
|
- A lock is just a variable
|
||||||
|
hl-page:: 339
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6433f4ba-f2e4-4743-a536-e2b7747433b7
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
|
- **lock variable**: some type of variable, which holds the *state* of the lock(and maybe additional data such as its holder or a queue for acquisition)
|
||||||
|
- **lock state**: available (or unlocked or free); acquired (or locked or held)
|
||||||
|
- **lock routines**:
|
||||||
|
- `lock()` tries to acquire the lock. If no other thread holds the lock, the thread will acquire the lock and enter the critical section(become the owner of the lock). Otherwise, it will not return while the lock is held by another thread.
|
||||||
|
- `unlock()` : The owner of the lock calls `unlock()`, then it is *available* again. If there are waiting threads, one of them will (eventually) notice (or be informed of) this change of the lock's state, acquire the lock, and enter the critical section.
|
||||||
|
- Locks help transform the chaos that is traditional OS scheduling into a more controlled activity
|
||||||
|
hl-page:: 340
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6433f5e6-bc06-42a9-866e-e9a3053f528f
|
||||||
|
hl-color:: yellow
|
||||||
|
- Controlling Interrupts
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 342
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6433fbfd-a1bf-4fd9-a54d-e15189c77b15
|
||||||
|
collapsed:: true
|
||||||
|
- For *single-processor* systems, **disable interrupts** for critical sections.
|
||||||
|
- Problems
|
||||||
|
- disable interrupts is privileged. In the worst case, the OS may never regain control when the interrupt isn't going to be enabled.
|
||||||
|
- does NOT work on multi-processor systems, each CPU has its own interrupt state
|
||||||
|
- importance interrupts may get lost
|
||||||
|
- inefficient
|
||||||
|
- Just Using Loads/Stores(Fail)
|
||||||
|
hl-page:: 343
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6433fe7e-2221-41ee-ad6b-7deaa4459aa5
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
|
- use a simple variable (flag) to indicate whether some thread has possession of a lock
|
||||||
|
hl-page:: 343
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6433ff4a-856d-4e4b-af30-6cb600aefeb5
|
||||||
|
hl-color:: yellow
|
||||||
|
- On acquisition, load, test the flag. If free, set the flag; If not free, spin-wait(loop load and test).
|
||||||
|
- On releasing, clear the flag.
|
||||||
|
- Problem
|
||||||
|
- When interrupted between load and test, *mutual exclusion* is broken.
|
||||||
|
- Low efficiency because of spin-waiting.
|
||||||
|
- **spin lock**
|
||||||
|
- ```c
|
||||||
|
void lock(lock_t *lock) {
|
||||||
|
while (TestAndSet(&lock->status, 1) == 1);
|
||||||
|
}
|
||||||
|
void unlock(lock_t *lock) { lock->status = 0; }
|
||||||
|
```
|
||||||
|
- Requires a preemptive scheduler(or it may spin forever)
|
||||||
|
- No fairness guarantee
|
||||||
|
- For single processor systems, terrible performance, because the thread holding the lock cannot make any progress to release the lock until it is scheduled again and thus all other threads waiting for the lock can do nothing but spinning even they are scheduled.
|
||||||
|
- For multi-processor systems, spin lock may work well when thread B on CPU1 waits for thread A on CPU0, and the critical section is short. Because lock owner keeps making progress, spinning doesn't waste many cycles.
|
||||||
|
- **Priority Inversion**: Threads with high priority wait for locks held by threads with low priority.
|
||||||
|
hl-page:: 355
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6435099b-0834-483e-9ef2-98a0b795cf00
|
||||||
|
hl-color:: yellow
|
||||||
|
Solution: **priority inheritance** or give up the priority?
|
||||||
|
- **Test-And-Set (Atomic Exchange)**
|
||||||
|
hl-page:: 344
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643401e0-fcec-41d3-9898-d5c4175ac464
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
|
- Returns the old value pointed to by the `old_ptr`, and simultaneously updates said value to `new`.
|
||||||
|
- "test" the old value (which is what is returned) while simultaneously "set" the memory location to a new value
|
||||||
|
- ```c
|
||||||
|
int TestAndSet(int *old_ptr, int new) {
|
||||||
|
int old = *old_ptr;
|
||||||
|
*old_ptr = new;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **Compare-And-Swap**
|
||||||
|
hl-page:: 348
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6434f8ac-d762-40a4-abb0-2955c2c8b396
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
|
- Test whether the value at the address specified by `ptr` is equal to `expected`.
|
||||||
|
hl-page:: 348
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6434fab0-08de-4f28-8d8e-f48f7e04aaaa
|
||||||
|
hl-color:: yellow
|
||||||
|
If so, update the memory location with the `new` value.
|
||||||
|
If not, do nothing.
|
||||||
|
Return the old value at the memory location.
|
||||||
|
- ```c
|
||||||
|
int CompareAndSwap(int *ptr, int expected, int new) {
|
||||||
|
int original = *ptr;
|
||||||
|
if (original == expected) *ptr = new;
|
||||||
|
return orginial
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Compare-and-swap flavor spin lock
|
||||||
|
```C
|
||||||
|
void lock(lock_t *lock) {
|
||||||
|
while (CompareAndSwap(&lock->status, 0, 1) == 1) ;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **load-linked** and **store-conditional**
|
||||||
|
hl-page:: 349
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6434fde1-9d19-4381-805e-f2a972875dc2
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
|
- The **load-linked** operates much like a typical load instruction, and simply fetches a value from memory and places it in a register.
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 349
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6434fe1c-47f3-422c-a317-be72f08d6aef
|
||||||
|
- **store-conditional** only succeeds if no intervening store to the address has taken place.
|
||||||
|
hl-page:: 349
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6434fe62-0e92-4414-86cc-b0c37fcf51ec
|
||||||
|
hl-color:: yellow
|
||||||
|
On success, return 1 and update the value at `ptr` to value.
|
||||||
|
On failure, return 0 and the value at `ptr` is not updated.
|
||||||
|
- ```c
|
||||||
|
int LL(int *ptr) { return *ptr; }
|
||||||
|
int SC(int *ptr, int value) {
|
||||||
|
if (/*no update to *ptr since LoadLinked to this address*/) {
|
||||||
|
*ptr = value;
|
||||||
|
return 1; // success!
|
||||||
|
} else {
|
||||||
|
return 0; // failed to update
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- LL/SC flavor spin lock: very similar to the errant Load/Store lock, but the special instructions here can detect intervening
|
||||||
|
```c
|
||||||
|
void lock(lock_t *lock) {
|
||||||
|
while (true) {
|
||||||
|
while (LL(&lock->status) == 1) ; // test
|
||||||
|
if (SC(&lock->status, 1) == 1) // set
|
||||||
|
break;
|
||||||
|
// else retry, in case lock->status is changed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **Fetch-And-Add**
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 350
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 64350170-c853-4080-9ed1-2777ea3a18c8
|
||||||
|
collapsed:: true
|
||||||
|
- Atomically increments a value while returning the old value at a particular address
|
||||||
|
- ```c
|
||||||
|
int FetchAndAdd(int *ptr) {
|
||||||
|
int old = *ptr;
|
||||||
|
*ptr = old + 1;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **ticket lock**
|
||||||
|
hl-page:: 351
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64350331-8fbb-4c41-9ac1-1a4ba852f772
|
||||||
|
hl-color:: yellow
|
||||||
|
- ```C
|
||||||
|
struct lock_t{
|
||||||
|
int ticket;
|
||||||
|
int turn;
|
||||||
|
};
|
||||||
|
void lock(lock_t *lock) {
|
||||||
|
int myturn = FetchAndAdd(&lock->ticket);
|
||||||
|
// atomically allocate a ticket as the thread's turn
|
||||||
|
while (lock->turn != myturn) ;
|
||||||
|
// wait for its turn
|
||||||
|
}
|
||||||
|
void unlock(lock_t *lock) {
|
||||||
|
lock->turn += 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Ensure progress for all threads. Once a thread is assigned its ticket value, it will be scheduled at some point in the future (i.e. it will definitely get its turn as `unlock()` operations increase global `turn` value).
|
||||||
|
hl-page:: 351
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64350420-ca8a-4cac-af2f-f4e7deb5d1be
|
||||||
|
hl-color:: yellow
|
||||||
|
In contrast, test-and-set spin lock may starve, if it is very unlucky.(never succeeds in contention)
|
||||||
|
- Simple Yield Lock
|
||||||
|
hl-page:: 353
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64350781-6995-41db-8b8e-2de0eb84136a
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
|
- `yield`: a system call that moves the caller from the running state to the ready state, and thus promotes another thread to running.
|
||||||
|
hl-page:: 353
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643507af-1153-46c1-b232-31a9a203e5df
|
||||||
|
hl-color:: yellow
|
||||||
|
- ```C
|
||||||
|
void lock(lock_t *lock) {
|
||||||
|
while (TestAndSet(&lock->status, 1) == 1)
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Problem: Starvation is still possible; Context switch overhead, though better than spinning
|
||||||
|
- Lock With Queues, Test-and-set, Yield, And Wakeup
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 354
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 64350b44-dfae-4544-93f9-ff2b343fefd4
|
||||||
|
- The real problem is: We have not much control over which thread to run next and thus causes potential waste.
|
||||||
|
hl-page:: 353
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64350b4e-9559-49d9-aa37-eda9fe425b7f
|
||||||
|
hl-color:: yellow
|
||||||
|
- `park()`: put a calling thread to sleep
|
||||||
|
hl-page:: 354
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64350bfb-64f7-4d41-8cc2-260dbec3372d
|
||||||
|
hl-color:: yellow
|
||||||
|
- `unpark(threadID)`: wake a particular thread
|
||||||
|
hl-page:: 354
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64350c01-39bb-4d15-b554-0287b13806ee
|
||||||
|
hl-color:: yellow
|
||||||
|
- implement
|
||||||
|
```C
|
||||||
|
struct lock_t{
|
||||||
|
int lk;
|
||||||
|
int guard; // spin lock for the whole lock
|
||||||
|
queue_t *q; // control who gets the lock next
|
||||||
|
};
|
||||||
|
void lock(lock_t *lock) {
|
||||||
|
while (TestAndSet(&m->guard, 1) == 1) ;
|
||||||
|
if (m->lk == 0) {
|
||||||
|
m->lk = 1;
|
||||||
|
m->guard = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m->q->add(get_tid());
|
||||||
|
setpark(); // newly added
|
||||||
|
m->guard = 0;
|
||||||
|
// ---- wakeup/waiting race ----
|
||||||
|
park();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void unlock(lock_t *lock) {
|
||||||
|
while (TestAndSet(&m->guard, 1) == 1) ;
|
||||||
|
if (m->q->empty())
|
||||||
|
m->flag = 0;
|
||||||
|
else
|
||||||
|
unpark(m->q->pop()); // should not clear flag here
|
||||||
|
// Wake up Only one waiting thread
|
||||||
|
m->guard = 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- When a thread is woken up, it will be as if it is returning from `park()`. Thus when `unpark` a thread, pass the lock directly from the thread releasing the lock to the next thread acquiring it; flag is not set to 0 in-between.
|
||||||
|
- wakeup/waiting race: If the thread is scheduled out just before it calls `park`, and then the lock owner calls `unpark` on that thread, it would sleep forever.
|
||||||
|
hl-page:: 356
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64351ba3-d4b5-4999-bc61-7733d5e0a061
|
||||||
|
hl-color:: yellow
|
||||||
|
- One solution is to use `setpark()`: indicate the thread is about to `park`. If it happens to be interrupted and another thread calls `unpark` before `park` is actually called, the subsequent park returns immediately instead of sleeping.
|
||||||
|
- Peterson's algorithm: mutual exclusion lock for 2 threads without hardware atomic instruction. Use 2 intention flags and a turn flag.
|
||||||
|
hl-page:: 345
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6434edd3-2a7b-4e11-af18-29854e628bc6
|
||||||
|
hl-color:: yellow
|
||||||
|
- **two-phase lock**
|
||||||
|
hl-page:: 358
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643522a7-4b16-4998-9b2f-47a852681a16
|
||||||
|
hl-color:: yellow
|
||||||
|
- A combination of spin lock and sleep lock
|
||||||
|
- In the first phase, the lock spins for a while, hoping that it can acquire the lock.
|
||||||
|
hl-page:: 358
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6435230e-d84a-4c91-8329-b7608b0d543a
|
||||||
|
hl-color:: yellow
|
||||||
|
- A second phase is entered if the lock is not acquired, where the caller is put to sleep, and only woken up when the lock becomes free later.
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 358
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 64352344-d140-468c-987c-e8afa05c2171
|
||||||
|
- Linux System Call **futex**
|
||||||
|
hl-page:: 356
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64351e9a-6505-4176-a6fb-ddf63f3245a8
|
||||||
|
hl-color:: yellow
|
||||||
|
- each `futex` is associated with ==a specific physical memory location==, and ==an in-kernel queue==
|
||||||
|
- `futex_wake(address)` wakes one thread that is waiting on the queue.
|
||||||
|
- `futex_wait(address, expected)` puts the calling thread to sleep, assuming the value at `address` is equal to `expected`. If it is not equal, the call returns immediately.
|
||||||
|
- Figure 28.10: Linux-based Futex Locks
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 357
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 64352221-d590-4371-a5f0-29e9cfa75ccb
|
||||||
|
- efficacy 功效,效力
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 341
|
||||||
|
hl-color:: green
|
||||||
|
id:: 6433fb69-1425-46b4-996f-f91da5d3e8d0
|
||||||
|
- foil
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 347
|
||||||
|
hl-color:: green
|
||||||
|
id:: 6434f523-44b7-40ab-8fea-528969c5acfd
|
||||||
|
- delve 钻研;探究;挖
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 349
|
||||||
|
hl-color:: green
|
||||||
|
id:: 6434fb8c-2b3b-4d80-83fb-3b34da4dcd28
|
||||||
|
- brag 吹嘘;自吹自擂
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 351
|
||||||
|
hl-color:: green
|
||||||
|
id:: 643501c1-f11b-4e85-8125-d2a5a31f69b0
|
||||||
|
- scourge
|
||||||
|
- 鞭打;鞭笞;折磨;使受苦难
|
||||||
|
- Lock-based Concurrent Data Structures
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 361
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 643525b0-e245-489b-877d-a2a1d63e7ea6
|
||||||
|
- **Concurrent Counters**
|
||||||
|
hl-page:: 361
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643525e5-fb85-48d4-905a-2a88b9ac0b0d
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
|
- **Counter with lock**
|
||||||
|
- Wrap the all the operations with a single lock.
|
||||||
|
- Performance is bad due to lock contention and it gets worse when the number of threads increases.
|
||||||
|
- **perfect scaling**: the increase in thread number doesn't harm the performance
|
||||||
|
hl-page:: 363
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64352751-d9bd-4d5e-a8ba-cd18f86b1a15
|
||||||
|
hl-color:: yellow
|
||||||
|
- **approximate counter**
|
||||||
|
hl-page:: 363
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64352794-d7c8-42f9-8321-f874967cebf2
|
||||||
|
hl-color:: yellow
|
||||||
|
- represent a single logical counter via ==numerous local physical counters==(one per CPU core), as well as ==a single global counter==. Each actual counter has a ==lock==.
|
||||||
|
- To add the counter, acquire the ==local lock== and increase it, thus avoiding contention.
|
||||||
|
- To read the counter, acquire the ==global lock== and read.
|
||||||
|
- To keep the global counter up to date, the local values are periodically transferred to the global counter and reset, which requires ==global lock and local lock==. A threshold `S` determines how often this transfer happens, tuning the trade-off between scalability and precision.
|
||||||
|
- **Concurrent Linked Lists**
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 367
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 643530d8-9d09-4c8a-9e92-47dfe814ef50
|
||||||
|
collapsed:: true
|
||||||
|
- Again, the simplest way to implement this is to wrap all operations on the list with a single lock.
|
||||||
|
- Assuming the `malloc` is ==thread-safe==, we can improve the code a little by narrowing critical section: only operations on global structure need to be locked.
|
||||||
|
- **hand-over-hand locking**: a lock per node.
|
||||||
|
hl-page:: 369
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64353237-4b74-4148-b7c1-5854d83a18c7
|
||||||
|
hl-color:: yellow
|
||||||
|
- When traversing the list, the code first grabs the next node's lock and then releases the current node's lock.
|
||||||
|
- In practice, it ==doesn't work== due to prohibitive overhead
|
||||||
|
- **Concurrent Queues**
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 370
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 64353353-9de2-421b-967d-dc80a597eecd
|
||||||
|
- Two locks, head and tail, for `enqueue` and `dequeue` operation.
|
||||||
|
- Add a dummy node to separate head and tail operation. Without this, `dequeue` operation needs to acquire both locks in case the queue is empty.
|
||||||
|
- **Concurrent Hash Table**
|
||||||
|
hl-page:: 372
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6435360d-c176-494a-9d61-b1fd0107a9bd
|
||||||
|
hl-color:: yellow
|
||||||
|
- instead of having a single lock for the entire structure, it uses a lock per hash bucket
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 372
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6435363d-c697-42a6-bfd0-8a2332cef394
|
||||||
|
- ubiquitous 似乎无所不在的;十分普遍的
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 372
|
||||||
|
hl-color:: green
|
||||||
|
id:: 6435365a-b5d6-46fc-a9a1-25b0d23aa529
|
||||||
|
- humble 谦逊;低声下气;虚心;贬低
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 373
|
||||||
|
hl-color:: green
|
||||||
|
id:: 6435367f-dd9e-449d-b0e4-3d8c9e14f6c2
|
||||||
|
- sloppy 马虎的,草率的;(衣服)宽松肥大的;太稀的,不够稠的;
|
||||||
|
hl-page:: 376
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643536c8-fc05-4bbe-8d1d-0f4f6d1c4fee
|
||||||
|
hl-color:: green
|
||||||
|
- gross 总的,毛的;严重的,极端的;粗鲁的;臃肿的;粗略的;
|
||||||
|
hl-page:: 378
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643537d3-7d01-442b-b47e-59433c2aa6db
|
||||||
|
hl-color:: green
|
||||||
|
- **condition variable**
|
||||||
|
hl-page:: 378
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643537ff-1028-4725-8d7a-c0338cc946d3
|
||||||
|
hl-color:: yellow
|
||||||
|
- A ==condition variable== is an explicit queue that threads can put themselves on when some state of execution(condition) is not as desired (by *waiting on the condition*); some other thread, when it changes said state, can then wake one (or more) of those waiting threads and thus allow them to continue (by *signaling*).
|
||||||
|
hl-page:: 378
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64353882-7697-4c16-8e53-c8f59ea256c1
|
||||||
|
hl-color:: yellow
|
||||||
|
- Operations
|
||||||
|
- `wait()` put the caller to sleep. `pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)`
|
||||||
|
hl-page:: 378
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643538d5-9ea3-4399-9fa2-d75fdf0e1dd4
|
||||||
|
hl-color:: yellow
|
||||||
|
- `signal()` wake up a sleeping thread waiting on this condition. `pthread_cond_signal(pthread_cond_t *c);`
|
||||||
|
hl-page:: 379
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643538de-cc40-4dd2-8f03-9492004f209b
|
||||||
|
hl-color:: yellow
|
||||||
|
- The `wait()` also takes a mutex as a parameter; it assumes that this mutex is locked when `wait()` is called. The responsibility of `wait()` is to ==release the lock and put the calling thread to sleep== (atomically); when the thread wakes up, it must ==re-acquire the lock before returning== to the caller. The design is helpful to avoid some race conditions when trying to sleep.
|
||||||
|
- use a while loop instead of just an if statement when deciding whether to wait on the condition.
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 380
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 643547c5-1613-49e9-899e-0e86f59a1462
|
||||||
|
- stem (花草的)茎;(花或叶的)梗,柄;阻止;封堵;遏止;
|
||||||
|
hl-page:: 379
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64353eb8-8ed8-4680-a3c0-91608b429408
|
||||||
|
hl-color:: green
|
||||||
|
- **stem from sth ** 是…的结果;起源于;根源是
|
||||||
|
- **producer/consumer problem**
|
||||||
|
hl-page:: 382
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64354974-adea-4b20-90f4-a12ebe1e4d5b
|
||||||
|
hl-color:: yellow
|
||||||
|
- **Mesa semantics**: Signaling a thread only wakes them up; it is thus a hint that the state of the world has ==changed==, but there is ==no guarantee== that when the woken thread runs, the state will ==still be as desired==. (Another guy may run before the thread and change the state again)
|
||||||
|
hl-page:: 385
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64354cc4-14c5-408d-b879-7d4d011b2b5c
|
||||||
|
hl-color:: yellow
|
||||||
|
- So, always use while loops. While loops make sure the thread wake up in the desired state of world, which tackles the ((64355502-f41f-40dd-b71f-e0abdbc76716)) and provides support for ((64355441-5a1b-4015-baa1-65917526079c))
|
||||||
|
hl-page:: 386
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64354db0-8c74-4c14-b063-d26378a10555
|
||||||
|
hl-color:: yellow
|
||||||
|
- **Hoare semantics**: provides a stronger guarantee that the woken thread will run immediately upon being woken
|
||||||
|
hl-page:: 386
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64354d46-4286-44fd-9e82-2ba562a50f25
|
||||||
|
hl-color:: yellow
|
||||||
|
- Incorrect Solution: single condition variable. The problem arises from the ==undirected wakeup operation==: God knows which thread is to be woken up.
|
||||||
|
- Envision multiple consumers and one producer:
|
||||||
|
1. producer `P1` increases count to 1, signals the CV and sleeps
|
||||||
|
2. consumer `C1` is awaken, reduces count to 0, signals the CV and sleeps
|
||||||
|
3. another consumer `C2` is woken up ==by accident==, finds out count is 0, sleeps
|
||||||
|
4. In this case, they all sleep and thus nobody will signal any of them
|
||||||
|
- If in step 3, the producer `P1` is woken up, everything is fine. Obviously, one solution is to ==exert control over which thread is to be woken up==. Well, wake up all threads may also solve this problem, see ((64355441-5a1b-4015-baa1-65917526079c)).
|
||||||
|
- Correct solution: 2 condition variable.
|
||||||
|
- Producer threads wait on the condition `empty`, and signals `fill`. Conversely, consumer threads wait on `fill` and signal `empty`.
|
||||||
|
- Code
|
||||||
|
```C
|
||||||
|
cond_t empty, fill;
|
||||||
|
mutex_t mutex;
|
||||||
|
void *producer(void *arg) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < loops; i++) {
|
||||||
|
Pthread_mutex_lock(&mutex);
|
||||||
|
while (count == MAX)
|
||||||
|
Pthread_cond_wait(&empty, &mutex);
|
||||||
|
put(i);
|
||||||
|
Pthread_cond_signal(&fill);
|
||||||
|
Pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void *consumer(void *arg) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < loops; i++) {
|
||||||
|
Pthread_mutex_lock(&mutex);
|
||||||
|
while (count == 0)
|
||||||
|
Pthread_cond_wait(&fill, &mutex);
|
||||||
|
int tmp = get();
|
||||||
|
Pthread_cond_signal(&empty);
|
||||||
|
Pthread_mutex_unlock(&mutex);
|
||||||
|
printf("%d\n", tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **spurious wakeups**
|
||||||
|
hl-page:: 390
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64355502-f41f-40dd-b71f-e0abdbc76716
|
||||||
|
hl-color:: yellow
|
||||||
|
- In some thread packages, due to details of the implementation, it is possible that two threads get woken up though just a single signal has taken place.
|
||||||
|
- **covering condition**
|
||||||
|
hl-page:: 391
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64355441-5a1b-4015-baa1-65917526079c
|
||||||
|
hl-color:: yellow
|
||||||
|
- covers all the cases where a thread needs to wake up, those unneeded simply wake up, re-check condition and go back to sleep
|
||||||
|
- `pthread_cond_broadcast()` wakes up all waiting threads
|
||||||
|
- albeit 尽管;虽然
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 390
|
||||||
|
hl-color:: green
|
||||||
|
id:: 64354f54-b26c-48dc-a328-4ae355b680f3
|
||||||
|
- spurious 虚假的;伪造的;建立在错误的观念(或思想方法)之上的;谬误的
|
||||||
|
hl-page:: 390
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643554f4-75a7-48fa-9366-87058ee723fb
|
||||||
|
hl-color:: green
|
||||||
|
- Semaphores
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 396
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 64356d96-cce8-48ad-80f1-e3e02a1a4684
|
||||||
|
- A semaphore is an ==object with an integer value== that we can manipulate with two routines `sem_wait()` and `sem_post()`. The initial value determines its behavior, so we need to give it an initial value through `sem_init()`
|
||||||
|
hl-page:: 396
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64356dba-48b4-49b8-8182-c962f12f03a5
|
||||||
|
hl-color:: yellow
|
||||||
|
- Semaphore: Definitions Of **Wait And Post**
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 397
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6435744b-a300-40ad-ba91-157666d8cd2a
|
||||||
|
collapsed:: true
|
||||||
|
- `sem_wait(sem_t *s)`: First decrement the value of the semaphore by one. Then wait if the value of semaphore is negative
|
||||||
|
- `sem_post(sem_t*s)`: First increment the value of the semaphore by one. If there is any thread waiting, wait up one of them
|
||||||
|
- The value of the semaphore, *when negative*, is equal to the ==number of waiting threads==
|
||||||
|
hl-page:: 397
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64357512-e25b-4226-961a-caec367fc8a3
|
||||||
|
hl-color:: yellow
|
||||||
|
- **Binary Semaphores (Locks)**
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 398
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6435753a-65b5-4e46-82bc-54c11c1cd533
|
||||||
|
collapsed:: true
|
||||||
|
- Initialize semaphore to 1, indicating we only have one piece of resource (the critical section).
|
||||||
|
- Wrap the critical section with `sem_wait` and `sem_post`
|
||||||
|
- When the lock is acquired, the semaphore is 0. On another acquisition request, the value goes to -1, which makes the caller sleep. When the lock is free, the value is decreased to 0 on acquisition, which will not get stuck.
|
||||||
|
- **Semaphores For Ordering (Condition Variable, or Ordering Primitive)**
|
||||||
|
hl-page:: 399
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64357930-2d96-4867-bc3d-2fe89990ce5f
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
|
- Initialize the semaphore to 0
|
||||||
|
- Consider the *join* operation. The parent calls `sem_wait`and the child calls `sem_post`. In either case, no matter which thread is scheduled first, the semaphore guarantees the desired result.
|
||||||
|
- **The Producer/Consumer (Bounded Buffer) Problem (Again)**
|
||||||
|
hl-page:: 401
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64357c6d-381e-492e-b901-095454f5315e
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
|
- 2 semaphores `empty` and `full` for coordination between consumer and producer, and 1 semaphore for lock
|
||||||
|
- Initialize `empty <- MAX`, and `full <- 0`
|
||||||
|
- Consumer waits for `full` and posts `empty` and conversely, produce waits for `empty` and posts `full`
|
||||||
|
- Special case for `MAX=1`
|
||||||
|
- When only one slot is available in the buffer, we don't even need a lock! Actually, it is binary semaphore which not only controls the buffer entry but also works as a lock.
|
||||||
|
- Otherwise, there will be a ==data race== inside the `put/get` operation due to potential multi-thread access to these procedures (when `MAX > 1`, the `sem_wait(&empty)` may allow in more than one thread).
|
||||||
|
- Deadlock avoidance
|
||||||
|
- If the lock semaphore is the outmost semaphore, deadlock occurs (the thread may sleep in `sem_wait(&empty)` with `mutex` unrelease). Therefore, put the lock inside the `empty/full` semaphore pair.
|
||||||
|
- Implement
|
||||||
|
```C
|
||||||
|
int empty = MAX, full = 0, mutex = 1;
|
||||||
|
void *producer() {
|
||||||
|
for (int i = 0; i < loops; ++ i) {
|
||||||
|
sem_wait(&empty);
|
||||||
|
sem_wait(&mutex);
|
||||||
|
put(i);
|
||||||
|
sem_post(&mutex);
|
||||||
|
sem_post(&full);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void *consumer() {
|
||||||
|
for (int i = 0; i < loops; ++ i) {
|
||||||
|
sem_wait(&full);
|
||||||
|
sem_wait(&mutex);
|
||||||
|
int tmp = get();
|
||||||
|
sem_post(&mutex);
|
||||||
|
sem_post(&empty);
|
||||||
|
printf("%d\n", tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **Reader-Writer Locks**
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 406
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 643583b4-26b1-4cbf-801c-11ed6e63976e
|
||||||
|
- Either allow ==multiple readers to read== concurrently, or allow ==only one writer to write==.
|
||||||
|
- Two sets of operation
|
||||||
|
- `rwlock_acquire/release_writelock()`: simply `wait/post` the `writelock`
|
||||||
|
- `rwlock_acquire/release_readlock()`: acquire `writelock` when the ==first reader acquires==, and release it when the ==last reader releases==
|
||||||
|
- Implement
|
||||||
|
```C
|
||||||
|
typedef struct _rwlock_t {
|
||||||
|
sem_t guard; // binary semaphore (basic lock)
|
||||||
|
sem_t writelock; // allow ONE writer/MANY readers
|
||||||
|
int readers; // #readers in critical section
|
||||||
|
} rwlock_t;
|
||||||
|
void rwlock_acquire_readlock(rwlock_t *rw) {
|
||||||
|
sem_wait(&rw->guard);
|
||||||
|
if (++rw->readers == 1) sem_wait(&rw->writelock);
|
||||||
|
sem_post(&rw->guard);
|
||||||
|
}
|
||||||
|
void rwlock_release_readlock(rwlock_t *rw) {
|
||||||
|
sem_wait(&rw->guard);
|
||||||
|
if (--rw->readers == 0) sem_post(&rw->writelock);
|
||||||
|
sem_post(&rw->guard);
|
||||||
|
}
|
||||||
|
void rwlock_acquire_writelock(rwlock_t *rw) { sem_wait(&rw->writelock); }
|
||||||
|
void rwlock_release_writelock(rwlock_t *rw) { sem_post(&rw->writelock); }
|
||||||
|
```
|
||||||
|
- Problem: More overhead; Unfairness, writer is much more likely to starve.
|
||||||
|
- To tackle the writer starvation problem, we may manually wake up the writers (if ever suspended) on read lock release. [Wiki](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock)
|
||||||
|
- **The Dining Philosophers**
|
||||||
|
hl-page:: 408
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 643587a7-ade4-4f09-be50-aea233ff02c0
|
||||||
|
hl-color:: yellow
|
||||||
|
- Background setting
|
||||||
|
hl-page:: 408
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6435889f-1375-4b94-8630-b3d0d7bdfa56
|
||||||
|
hl-color:: yellow
|
||||||
|
- 5 "philosophers" around a table.
|
||||||
|
Between each pair of philosophers is a single fork (and thus, 5 total).
|
||||||
|
The philosophers each have times where they think (don’t need forks), and times where they eat.
|
||||||
|
In order to eat, a philosopher needs two forks (left and right).
|
||||||
|
The contention for these forks is our synchronization problem.
|
||||||
|
- Solution
|
||||||
|
- A semaphore per fork, and helper function `left/right(p)` which is the fork on philosopher `p`'s left/right.
|
||||||
|
- Deadlock: if each philosopher tries to grab the fork on their left first, there will be a deadlock. When all of them get their left-side forks, all of the forks are locked and no one could get their right-side fork.
|
||||||
|
- Non-deadlock: force one philosopher to try to grab the right-side fork first
|
||||||
|
- Implement
|
||||||
|
```C
|
||||||
|
void put_forks(int p) {
|
||||||
|
sem_post(&forks[left(p)]);
|
||||||
|
sem_post(&forks[right(p)]);
|
||||||
|
}
|
||||||
|
void get_forks(int p) {
|
||||||
|
if (p == 4) {
|
||||||
|
sem_wait(&forks[right(p)]);
|
||||||
|
sem_wait(&forks[left(p)]);
|
||||||
|
} else {
|
||||||
|
sem_wait(&forks[left(p)]);
|
||||||
|
sem_wait(&forks[right(p)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void philosopher() {
|
||||||
|
while (1) {
|
||||||
|
think();
|
||||||
|
get_forks(p);
|
||||||
|
eat();
|
||||||
|
put_forks(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Implement Semaphores
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 411
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 643589a6-31e6-4603-9259-999e9c8860f7
|
||||||
|
- Implementing Zemaphores With One Lock And One CV: the book authors provide us a simple implement for semaphore, though somewhat different from its definition.
|
||||||
|
hl-page:: 412
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64358de1-f418-44fd-8a77-bc0faa368059
|
||||||
|
hl-color:: yellow
|
||||||
|
- salient 最重要的;显着的;突出的:
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 397
|
||||||
|
hl-color:: green
|
||||||
|
id:: 64357404-d348-42b3-96a3-ba28575baa66
|
||||||
|
- ensue 跟着发生,接着发生;
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 408
|
||||||
|
hl-color:: green
|
||||||
|
id:: 64358802-3b22-46ed-a0e2-71cc9df69a7b
|
||||||
|
- Throttle 节流阀;风门;喉咙;使窒息;使节流;
|
||||||
|
hl-page:: 411
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64358758-cb9c-4e8d-aaa4-f8e50457db88
|
||||||
|
hl-color:: green
|
||||||
|
- bog 沼泽;泥塘;使陷于泥沼;使动弹不得
|
||||||
|
hl-page:: 411
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64358755-1fae-4ea2-93a3-8c9d3d3e11c3
|
||||||
|
hl-color:: green
|
||||||
|
- ramification (众多复杂而又难以预料的)结果,后果
|
||||||
|
hl-page:: 410
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 64358b0c-e441-4d0a-852d-ecfde369306c
|
||||||
|
hl-color:: green
|
||||||
@ -342,7 +342,7 @@
|
|||||||
;; ;use triple underscore `___` for slash `/` in page title
|
;; ;use triple underscore `___` for slash `/` in page title
|
||||||
;; ;use Percent-encoding for other invalid characters
|
;; ;use Percent-encoding for other invalid characters
|
||||||
:file/name-format :triple-lowbar
|
:file/name-format :triple-lowbar
|
||||||
:ui/show-brackets? false
|
:ui/show-brackets? true
|
||||||
|
|
||||||
;; specify the format of the filename for journal files
|
;; specify the format of the filename for journal files
|
||||||
;; :journal/file-name-format "yyyy_MM_dd"
|
;; :journal/file-name-format "yyyy_MM_dd"
|
||||||
|
|||||||
@ -117,3 +117,130 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
- Dining Philosopher Solution with Semaphore
|
||||||
|
id:: 6436bebd-0681-4f94-9d04-4d8e4a554512
|
||||||
|
- ```C
|
||||||
|
void put_forks(int p) {
|
||||||
|
sem_post(&forks[left(p)]);
|
||||||
|
sem_post(&forks[right(p)]);
|
||||||
|
}
|
||||||
|
void get_forks(int p) {
|
||||||
|
if (p == 4) {
|
||||||
|
sem_wait(&forks[right(p)]);
|
||||||
|
sem_wait(&forks[left(p)]);
|
||||||
|
} else {
|
||||||
|
sem_wait(&forks[left(p)]);
|
||||||
|
sem_wait(&forks[right(p)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void philosopher() {
|
||||||
|
while (1) {
|
||||||
|
think();
|
||||||
|
get_forks(p);
|
||||||
|
eat();
|
||||||
|
put_forks(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Simple Semaphore Implement
|
||||||
|
id:: 6436c47e-dc86-4452-b9b5-4e7997dbfbfb
|
||||||
|
- ```C
|
||||||
|
struct sem_t{
|
||||||
|
int value;
|
||||||
|
cond_t cond;
|
||||||
|
mutex_t lock;
|
||||||
|
};
|
||||||
|
void sem_wait(sem_t *sem) {
|
||||||
|
mutex_lock(&sem->lock);
|
||||||
|
while (s->value <= 0)
|
||||||
|
cond_wait(&sem->cond, &sem->lock);
|
||||||
|
s->value --;
|
||||||
|
mutex_unlock(&sem->lock);
|
||||||
|
}
|
||||||
|
void sem_post(sem_t *sem) {
|
||||||
|
mutex_lock(&sem->lock);
|
||||||
|
sem->value ++;
|
||||||
|
cond_signal(&sem->cond);
|
||||||
|
mutex_unlock(&sem->lock);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Compare-And-Swap Code Description
|
||||||
|
id:: 6436c5c7-32e7-4071-b909-4fdc14bb479d
|
||||||
|
- ```c
|
||||||
|
int CompareAndSwap(int *ptr, int expected, int new) {
|
||||||
|
int original = *ptr;
|
||||||
|
if (original == expected) *ptr = new;
|
||||||
|
return orginial
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Compare-and-swap flavor spin lock
|
||||||
|
id:: b7679e9b-aabe-4bd3-8c2c-eb0a23fad491
|
||||||
|
- ```C
|
||||||
|
void lock(lock_t *lock) {
|
||||||
|
while (CompareAndSwap(&lock->status, 0, 1) == 1) ;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- LL/SC Code Description
|
||||||
|
id:: 6436c620-4884-45a7-9273-b7952a6521ae
|
||||||
|
- ```c
|
||||||
|
int LL(int *ptr) { return *ptr; }
|
||||||
|
int SC(int *ptr, int value) {
|
||||||
|
if (/*no update to *ptr since LoadLinked to this address*/) {
|
||||||
|
*ptr = value;
|
||||||
|
return 1; // success!
|
||||||
|
} else {
|
||||||
|
return 0; // failed to update
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- LL/SC flavor spin lock
|
||||||
|
id:: c38274a9-22dd-40e2-b74a-d3a9be63600e
|
||||||
|
- very similar to the errant Load/Store lock, but the special instructions here can detect intervening
|
||||||
|
```c
|
||||||
|
void lock(lock_t *lock) {
|
||||||
|
while (true) {
|
||||||
|
while (LL(&lock->status) == 1) ; // test
|
||||||
|
if (SC(&lock->status, 1) == 1) // set
|
||||||
|
break;
|
||||||
|
// else retry, in case lock->status is changed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Simple Yield Lock Code
|
||||||
|
id:: 6436c684-ac4a-4144-9e7e-b4cb8f976c1f
|
||||||
|
- ```C
|
||||||
|
void lock(lock_t *lock) {
|
||||||
|
while (TestAndSet(&lock->status, 1) == 1)
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Fetch-And-Add Code Description
|
||||||
|
id:: 6436c66c-807b-4e9d-93ed-b1d9703e6dc2
|
||||||
|
- ```C
|
||||||
|
int FetchAndAdd(int *ptr) {
|
||||||
|
int old = *ptr;
|
||||||
|
*ptr = old + 1;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Readers-Writer Lock Implement
|
||||||
|
id:: 6436c668-5be8-4ce1-b701-1f2a00d34cc9
|
||||||
|
- ```C
|
||||||
|
typedef struct _rwlock_t {
|
||||||
|
sem_t guard; // binary semaphore (basic lock)
|
||||||
|
sem_t writelock; // allow ONE writer/MANY readers
|
||||||
|
int readers; // #readers in critical section
|
||||||
|
} rwlock_t;
|
||||||
|
void rwlock_acquire_readlock(rwlock_t *rw) {
|
||||||
|
sem_wait(&rw->guard);
|
||||||
|
if (++rw->readers == 1) sem_wait(&rw->writelock);
|
||||||
|
sem_post(&rw->guard);
|
||||||
|
}
|
||||||
|
void rwlock_release_readlock(rwlock_t *rw) {
|
||||||
|
sem_wait(&rw->guard);
|
||||||
|
if (--rw->readers == 0) sem_post(&rw->writelock);
|
||||||
|
sem_post(&rw->guard);
|
||||||
|
}
|
||||||
|
void rwlock_acquire_writelock(rwlock_t *rw) { sem_wait(&rw->writelock); }
|
||||||
|
void rwlock_release_writelock(rwlock_t *rw) { sem_post(&rw->writelock); }
|
||||||
|
```
|
||||||
@ -2,11 +2,12 @@ file:: [ostep_1681115599584_0.pdf](../assets/ostep_1681115599584_0.pdf)
|
|||||||
file-path:: ../assets/ostep_1681115599584_0.pdf
|
file-path:: ../assets/ostep_1681115599584_0.pdf
|
||||||
|
|
||||||
- # Part II
|
- # Part II
|
||||||
- thread
|
- ## thread
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
hl-page:: 311
|
hl-page:: 311
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
id:: 6433ca28-1bdf-433d-8ed9-0d54bf5ba940
|
id:: 6433ca28-1bdf-433d-8ed9-0d54bf5ba940
|
||||||
|
collapsed:: true
|
||||||
- share the same address space and thus can access the same data
|
- share the same address space and thus can access the same data
|
||||||
- context switch: the address space remains the same
|
- context switch: the address space remains the same
|
||||||
hl-page:: 311
|
hl-page:: 311
|
||||||
@ -24,6 +25,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
id:: 6433cba2-61bd-4549-a29f-2ad85b3e30cd
|
id:: 6433cba2-61bd-4549-a29f-2ad85b3e30cd
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
- Why thread?
|
- Why thread?
|
||||||
|
collapsed:: true
|
||||||
- possible speedup through parallelization
|
- possible speedup through parallelization
|
||||||
- enable overlap of IO in a single program
|
- enable overlap of IO in a single program
|
||||||
- Though these could be done through multi-processing, threading makes share data easier
|
- Though these could be done through multi-processing, threading makes share data easier
|
||||||
@ -32,6 +34,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
hl-page:: 323
|
hl-page:: 323
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
id:: 6433eabf-48d6-4776-b66f-a5f7804d1ddc
|
id:: 6433eabf-48d6-4776-b66f-a5f7804d1ddc
|
||||||
|
collapsed:: true
|
||||||
- **indeterminate**: the results depend on the timing execution of the code.
|
- **indeterminate**: the results depend on the timing execution of the code.
|
||||||
- race condition
|
- race condition
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
@ -68,12 +71,14 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 6433f35b-403b-4b25-b9f9-076e9e34777e
|
id:: 6433f35b-403b-4b25-b9f9-076e9e34777e
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
- `pthread_create` `pthread_join` `pthread_mutex_lock` `pthread_cond_*`
|
- `pthread_create` `pthread_join` `pthread_mutex_lock` `pthread_cond_*`
|
||||||
- Locks
|
- ## Locks
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
hl-page:: 339
|
hl-page:: 339
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
id:: 6433f45b-0345-4790-8379-3d1a94e57ef5
|
id:: 6433f45b-0345-4790-8379-3d1a94e57ef5
|
||||||
|
collapsed:: true
|
||||||
- A lock is just a variable
|
- A lock is just a variable
|
||||||
hl-page:: 339
|
hl-page:: 339
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
@ -96,8 +101,8 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
id:: 6433fbfd-a1bf-4fd9-a54d-e15189c77b15
|
id:: 6433fbfd-a1bf-4fd9-a54d-e15189c77b15
|
||||||
- For *single-processor* systems, **disable interrupts** for critical sections.
|
- For *single-processor* systems, **disable interrupts** for critical sections.
|
||||||
- Problems
|
- Problems
|
||||||
- disable interrupts is privileged. In the worst case, the OS may never regain control when the interrupt isn't going to be enabled.
|
- Disable interrupts is a privileged instruction. In the worst case, the OS may never regain control when the interrupt isn't going to be enabled.
|
||||||
- does NOT work on multi-processor systems, each CPU has its own interrupt state
|
- NOT work on multi-processor systems, each CPU has its own interrupt state
|
||||||
- importance interrupts may get lost
|
- importance interrupts may get lost
|
||||||
- inefficient
|
- inefficient
|
||||||
- Just Using Loads/Stores(Fail)
|
- Just Using Loads/Stores(Fail)
|
||||||
@ -147,19 +152,8 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
If so, update the memory location with the `new` value.
|
If so, update the memory location with the `new` value.
|
||||||
If not, do nothing.
|
If not, do nothing.
|
||||||
Return the old value at the memory location.
|
Return the old value at the memory location.
|
||||||
- ```c
|
- ((6436c5c7-32e7-4071-b909-4fdc14bb479d))
|
||||||
int CompareAndSwap(int *ptr, int expected, int new) {
|
- ((b7679e9b-aabe-4bd3-8c2c-eb0a23fad491))
|
||||||
int original = *ptr;
|
|
||||||
if (original == expected) *ptr = new;
|
|
||||||
return orginial
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Compare-and-swap flavor spin lock
|
|
||||||
```C
|
|
||||||
void lock(lock_t *lock) {
|
|
||||||
while (CompareAndSwap(&lock->status, 0, 1) == 1) ;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- **load-linked** and **store-conditional**
|
- **load-linked** and **store-conditional**
|
||||||
hl-page:: 349
|
hl-page:: 349
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
@ -177,41 +171,15 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
On success, return 1 and update the value at `ptr` to value.
|
On success, return 1 and update the value at `ptr` to value.
|
||||||
On failure, return 0 and the value at `ptr` is not updated.
|
On failure, return 0 and the value at `ptr` is not updated.
|
||||||
- ```c
|
- ((6436c620-4884-45a7-9273-b7952a6521ae))
|
||||||
int LL(int *ptr) { return *ptr; }
|
- ((c38274a9-22dd-40e2-b74a-d3a9be63600e))
|
||||||
int SC(int *ptr, int value) {
|
|
||||||
if (/*no update to *ptr since LoadLinked to this address*/) {
|
|
||||||
*ptr = value;
|
|
||||||
return 1; // success!
|
|
||||||
} else {
|
|
||||||
return 0; // failed to update
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- LL/SC flavor spin lock: very similar to the errant Load/Store lock, but the special instructions here can detect intervening
|
|
||||||
```c
|
|
||||||
void lock(lock_t *lock) {
|
|
||||||
while (true) {
|
|
||||||
while (LL(&lock->status) == 1) ; // test
|
|
||||||
if (SC(&lock->status, 1) == 1) // set
|
|
||||||
break;
|
|
||||||
// else retry, in case lock->status is changed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- **Fetch-And-Add**
|
- **Fetch-And-Add**
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
hl-page:: 350
|
hl-page:: 350
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
id:: 64350170-c853-4080-9ed1-2777ea3a18c8
|
id:: 64350170-c853-4080-9ed1-2777ea3a18c8
|
||||||
- Atomically increments a value while returning the old value at a particular address
|
- Atomically increments a value while returning the old value at a particular address
|
||||||
- ```c
|
- ((6436c66c-807b-4e9d-93ed-b1d9703e6dc2))
|
||||||
int FetchAndAdd(int *ptr) {
|
|
||||||
int old = *ptr;
|
|
||||||
*ptr = old + 1;
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- **ticket lock**
|
- **ticket lock**
|
||||||
hl-page:: 351
|
hl-page:: 351
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
@ -224,7 +192,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
id:: 64350420-ca8a-4cac-af2f-f4e7deb5d1be
|
id:: 64350420-ca8a-4cac-af2f-f4e7deb5d1be
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
In contrast, test-and-set spin lock may starve, if it is very unlucky.(never succeeds in contention)
|
In contrast, test-and-set spin lock may starve, if it is very unlucky.(never succeeds in contention)
|
||||||
- Simple Yield Lock
|
- Simple **Yield Lock**
|
||||||
hl-page:: 353
|
hl-page:: 353
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 64350781-6995-41db-8b8e-2de0eb84136a
|
id:: 64350781-6995-41db-8b8e-2de0eb84136a
|
||||||
@ -234,14 +202,9 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 643507af-1153-46c1-b232-31a9a203e5df
|
id:: 643507af-1153-46c1-b232-31a9a203e5df
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
- ```C
|
- ((6436c684-ac4a-4144-9e7e-b4cb8f976c1f))
|
||||||
void lock(lock_t *lock) {
|
|
||||||
while (TestAndSet(&lock->status, 1) == 1)
|
|
||||||
yield();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Problem: Starvation is still possible; Context switch overhead, though better than spinning
|
- Problem: Starvation is still possible; Context switch overhead, though better than spinning
|
||||||
- Lock With Queues, Test-and-set, Yield, And Wakeup
|
- **Lock With Queues**, Test-and-set, Yield, And Wakeup
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
hl-page:: 354
|
hl-page:: 354
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
@ -324,11 +287,12 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
hl-color:: green
|
hl-color:: green
|
||||||
id:: 643501c1-f11b-4e85-8125-d2a5a31f69b0
|
id:: 643501c1-f11b-4e85-8125-d2a5a31f69b0
|
||||||
- scourge 鞭打;鞭笞;折磨;使受苦难
|
- scourge 鞭打;鞭笞;折磨;使受苦难
|
||||||
- Lock-based Concurrent Data Structures
|
- ## Lock-based Concurrent Data Structures
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
hl-page:: 361
|
hl-page:: 361
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
id:: 643525b0-e245-489b-877d-a2a1d63e7ea6
|
id:: 643525b0-e245-489b-877d-a2a1d63e7ea6
|
||||||
|
collapsed:: true
|
||||||
- **Concurrent Counters**
|
- **Concurrent Counters**
|
||||||
hl-page:: 361
|
hl-page:: 361
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
@ -372,6 +336,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
hl-page:: 370
|
hl-page:: 370
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
id:: 64353353-9de2-421b-967d-dc80a597eecd
|
id:: 64353353-9de2-421b-967d-dc80a597eecd
|
||||||
|
collapsed:: true
|
||||||
- Two locks, head and tail, for `enqueue` and `dequeue` operation.
|
- Two locks, head and tail, for `enqueue` and `dequeue` operation.
|
||||||
- Add a dummy node to separate head and tail operation. Without this, `dequeue` operation needs to acquire both locks in case the queue is empty.
|
- Add a dummy node to separate head and tail operation. Without this, `dequeue` operation needs to acquire both locks in case the queue is empty.
|
||||||
- **Concurrent Hash Table**
|
- **Concurrent Hash Table**
|
||||||
@ -379,6 +344,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 6435360d-c176-494a-9d61-b1fd0107a9bd
|
id:: 6435360d-c176-494a-9d61-b1fd0107a9bd
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
- instead of having a single lock for the entire structure, it uses a lock per hash bucket
|
- instead of having a single lock for the entire structure, it uses a lock per hash bucket
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
hl-page:: 372
|
hl-page:: 372
|
||||||
@ -404,7 +370,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 643537d3-7d01-442b-b47e-59433c2aa6db
|
id:: 643537d3-7d01-442b-b47e-59433c2aa6db
|
||||||
hl-color:: green
|
hl-color:: green
|
||||||
- **condition variable**
|
- ## condition variable
|
||||||
hl-page:: 378
|
hl-page:: 378
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 643537ff-1028-4725-8d7a-c0338cc946d3
|
id:: 643537ff-1028-4725-8d7a-c0338cc946d3
|
||||||
@ -437,7 +403,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
id:: 64353eb8-8ed8-4680-a3c0-91608b429408
|
id:: 64353eb8-8ed8-4680-a3c0-91608b429408
|
||||||
hl-color:: green
|
hl-color:: green
|
||||||
- **stem from sth ** 是…的结果;起源于;根源是
|
- **stem from sth ** 是…的结果;起源于;根源是
|
||||||
- **producer/consumer problem**
|
- **Producer/Consumer Problem**
|
||||||
hl-page:: 382
|
hl-page:: 382
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 64354974-adea-4b20-90f4-a12ebe1e4d5b
|
id:: 64354974-adea-4b20-90f4-a12ebe1e4d5b
|
||||||
@ -478,7 +444,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 64355441-5a1b-4015-baa1-65917526079c
|
id:: 64355441-5a1b-4015-baa1-65917526079c
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
- covers all the cases where a thread needs to wake up, those unneeded simply wake up, re-check condition and go back to sleep
|
- covers all the cases where a thread needs to wake up, other threads simply wake up, re-check condition and go back to sleep
|
||||||
- `pthread_cond_broadcast()` wakes up all waiting threads
|
- `pthread_cond_broadcast()` wakes up all waiting threads
|
||||||
- albeit 尽管;虽然
|
- albeit 尽管;虽然
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
@ -490,11 +456,12 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 643554f4-75a7-48fa-9366-87058ee723fb
|
id:: 643554f4-75a7-48fa-9366-87058ee723fb
|
||||||
hl-color:: green
|
hl-color:: green
|
||||||
- Semaphores
|
- ## Semaphores
|
||||||
ls-type:: annotation
|
|
||||||
hl-page:: 396
|
hl-page:: 396
|
||||||
hl-color:: yellow
|
ls-type:: annotation
|
||||||
id:: 64356d96-cce8-48ad-80f1-e3e02a1a4684
|
id:: 64356d96-cce8-48ad-80f1-e3e02a1a4684
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
- A semaphore is an ==object with an integer value== that we can manipulate with two routines `sem_wait()` and `sem_post()`. The initial value determines its behavior, so we need to give it an initial value through `sem_init()`
|
- A semaphore is an ==object with an integer value== that we can manipulate with two routines `sem_wait()` and `sem_post()`. The initial value determines its behavior, so we need to give it an initial value through `sem_init()`
|
||||||
hl-page:: 396
|
hl-page:: 396
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
@ -540,8 +507,8 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
- Otherwise, there will be a ==data race== inside the `put/get` operation due to potential multi-thread access to these procedures (when `MAX > 1`, the `sem_wait(&empty)` may allow in more than one thread).
|
- Otherwise, there will be a ==data race== inside the `put/get` operation due to potential multi-thread access to these procedures (when `MAX > 1`, the `sem_wait(&empty)` may allow in more than one thread).
|
||||||
- Deadlock avoidance
|
- Deadlock avoidance
|
||||||
- If the lock semaphore is the outmost semaphore, deadlock occurs (the thread may sleep in `sem_wait(&empty)` with `mutex` unrelease). Therefore, put the lock inside the `empty/full` semaphore pair.
|
- If the lock semaphore is the outmost semaphore, deadlock occurs (the thread may sleep in `sem_wait(&empty)` with `mutex` unrelease). Therefore, put the lock inside the `empty/full` semaphore pair.
|
||||||
- Implement
|
- ((6436bebd-0681-4f94-9d04-4d8e4a554512))
|
||||||
- **Reader-Writer Locks**
|
- **Readers-Writer Locks**
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
hl-page:: 406
|
hl-page:: 406
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
@ -550,26 +517,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
- Two sets of operation
|
- Two sets of operation
|
||||||
- `rwlock_acquire/release_writelock()`: simply `wait/post` the `writelock`
|
- `rwlock_acquire/release_writelock()`: simply `wait/post` the `writelock`
|
||||||
- `rwlock_acquire/release_readlock()`: acquire `writelock` when the ==first reader acquires==, and release it when the ==last reader releases==
|
- `rwlock_acquire/release_readlock()`: acquire `writelock` when the ==first reader acquires==, and release it when the ==last reader releases==
|
||||||
- Implement
|
- ((6436c668-5be8-4ce1-b701-1f2a00d34cc9))
|
||||||
```C
|
|
||||||
typedef struct _rwlock_t {
|
|
||||||
sem_t guard; // binary semaphore (basic lock)
|
|
||||||
sem_t writelock; // allow ONE writer/MANY readers
|
|
||||||
int readers; // #readers in critical section
|
|
||||||
} rwlock_t;
|
|
||||||
void rwlock_acquire_readlock(rwlock_t *rw) {
|
|
||||||
sem_wait(&rw->guard);
|
|
||||||
if (++rw->readers == 1) sem_wait(&rw->writelock);
|
|
||||||
sem_post(&rw->guard);
|
|
||||||
}
|
|
||||||
void rwlock_release_readlock(rwlock_t *rw) {
|
|
||||||
sem_wait(&rw->guard);
|
|
||||||
if (--rw->readers == 0) sem_post(&rw->writelock);
|
|
||||||
sem_post(&rw->guard);
|
|
||||||
}
|
|
||||||
void rwlock_acquire_writelock(rwlock_t *rw) { sem_wait(&rw->writelock); }
|
|
||||||
void rwlock_release_writelock(rwlock_t *rw) { sem_post(&rw->writelock); }
|
|
||||||
```
|
|
||||||
- Problem: More overhead; Unfairness, writer is much more likely to starve.
|
- Problem: More overhead; Unfairness, writer is much more likely to starve.
|
||||||
- To tackle the writer starvation problem, we may manually wake up the writers (if ever suspended) every time read lock releases. [Wiki](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock)
|
- To tackle the writer starvation problem, we may manually wake up the writers (if ever suspended) every time read lock releases. [Wiki](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock)
|
||||||
- **The Dining Philosophers**
|
- **The Dining Philosophers**
|
||||||
@ -591,30 +539,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
- A semaphore per fork, and helper function `left/right(p)` which is the fork on philosopher `p`'s left/right.
|
- A semaphore per fork, and helper function `left/right(p)` which is the fork on philosopher `p`'s left/right.
|
||||||
- Deadlock: if each philosopher tries to grab the fork on their left first, there will be a deadlock. When all of them get their left-side forks, all of the forks are locked and no one could get their right-side fork.
|
- Deadlock: if each philosopher tries to grab the fork on their left first, there will be a deadlock. When all of them get their left-side forks, all of the forks are locked and no one could get their right-side fork.
|
||||||
- Non-deadlock: force one philosopher to try to grab the right-side fork first
|
- Non-deadlock: force one philosopher to try to grab the right-side fork first
|
||||||
- Implement
|
- ((6436bebd-0681-4f94-9d04-4d8e4a554512))
|
||||||
```C
|
|
||||||
void put_forks(int p) {
|
|
||||||
sem_post(&forks[left(p)]);
|
|
||||||
sem_post(&forks[right(p)]);
|
|
||||||
}
|
|
||||||
void get_forks(int p) {
|
|
||||||
if (p == 4) {
|
|
||||||
sem_wait(&forks[right(p)]);
|
|
||||||
sem_wait(&forks[left(p)]);
|
|
||||||
} else {
|
|
||||||
sem_wait(&forks[left(p)]);
|
|
||||||
sem_wait(&forks[right(p)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void philosopher() {
|
|
||||||
while (1) {
|
|
||||||
think();
|
|
||||||
get_forks(p);
|
|
||||||
eat();
|
|
||||||
put_forks(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Implement Semaphores
|
- Implement Semaphores
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
hl-page:: 411
|
hl-page:: 411
|
||||||
@ -625,27 +550,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 64358de1-f418-44fd-8a77-bc0faa368059
|
id:: 64358de1-f418-44fd-8a77-bc0faa368059
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
- Implement
|
- ((6436c47e-dc86-4452-b9b5-4e7997dbfbfb))
|
||||||
```C
|
|
||||||
struct sem_t{
|
|
||||||
int value;
|
|
||||||
cond_t cond;
|
|
||||||
mutex_t lock;
|
|
||||||
};
|
|
||||||
void sem_wait(sem_t *sem) {
|
|
||||||
mutex_lock(&sem->lock);
|
|
||||||
while (s->value <= 0)
|
|
||||||
cond_wait(&sem->cond, &sem->lock);
|
|
||||||
s->value --;
|
|
||||||
mutex_unlock(&sem->lock);
|
|
||||||
}
|
|
||||||
void sem_post(sem_t *sem) {
|
|
||||||
mutex_lock(&sem->lock);
|
|
||||||
sem->value ++;
|
|
||||||
cond_signal(&sem->cond);
|
|
||||||
mutex_unlock(&sem->lock);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- salient 最重要的;显着的;突出的:
|
- salient 最重要的;显着的;突出的:
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
hl-page:: 397
|
hl-page:: 397
|
||||||
@ -671,16 +576,17 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 64358b0c-e441-4d0a-852d-ecfde369306c
|
id:: 64358b0c-e441-4d0a-852d-ecfde369306c
|
||||||
hl-color:: green
|
hl-color:: green
|
||||||
- Non-Deadlock Bugs: A large fraction (97%) of non-deadlock bugs studied by Lu et al. are either ==atomicity violations== or ==order violations==.
|
- **Non-Deadlock Bugs**: A large fraction (97%) of non-deadlock bugs studied by Lu et al. are either ==atomicity violations== or ==order violations==.
|
||||||
hl-page:: 420
|
hl-page:: 420
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 64361e4c-62eb-4599-9809-0f77f9ce1cd0
|
id:: 64361e4c-62eb-4599-9809-0f77f9ce1cd0
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
- **Deadlock**
|
- ## Deadlock
|
||||||
ls-type:: annotation
|
|
||||||
hl-page:: 420
|
hl-page:: 420
|
||||||
hl-color:: yellow
|
ls-type:: annotation
|
||||||
id:: 64361fb7-5aa6-45cd-8b1e-aa0d0c300ad2
|
id:: 64361fb7-5aa6-45cd-8b1e-aa0d0c300ad2
|
||||||
|
hl-color:: yellow
|
||||||
|
collapsed:: true
|
||||||
- **Conditions for Deadlock**
|
- **Conditions for Deadlock**
|
||||||
hl-page:: 422
|
hl-page:: 422
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
@ -769,11 +675,11 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
hl-page:: 432
|
hl-page:: 432
|
||||||
hl-color:: green
|
hl-color:: green
|
||||||
id:: 64364569-01b4-45e1-83f8-ac1bd8af5850
|
id:: 64364569-01b4-45e1-83f8-ac1bd8af5850
|
||||||
- **Event-based Concurrency**
|
- ## Event-based Concurrency
|
||||||
ls-type:: annotation
|
|
||||||
hl-page:: 432
|
hl-page:: 432
|
||||||
hl-color:: yellow
|
ls-type:: annotation
|
||||||
id:: 64364585-ace4-4920-87fe-87aad004dffd
|
id:: 64364585-ace4-4920-87fe-87aad004dffd
|
||||||
|
hl-color:: yellow
|
||||||
- event loop: waits for something to do and then, for each event returned, processes them, one at a time
|
- event loop: waits for something to do and then, for each event returned, processes them, one at a time
|
||||||
hl-page:: 433
|
hl-page:: 433
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
@ -825,7 +731,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
- Checking IO completion is inefficient, perhaps we need interrupt-based approaches (e.g. UNIX signals) to inform applications when async IO completes.
|
- Checking IO completion is inefficient, perhaps we need interrupt-based approaches (e.g. UNIX signals) to inform applications when async IO completes.
|
||||||
- Problems
|
- Problems
|
||||||
- State management
|
- State management
|
||||||
- manual stack management: when an event handler issues an asynchronous I/O, it must package up some program state for the next event handler to use when the I/O finally completes; this additional work is not needed in thread-based programs, as the state the program needs is on the stack of the thread.
|
- manual stack management: when an event handler issues an asynchronous I/O, it must package up some ==program state for the next event handler== to use when the I/O finally completes; this additional work is ==not needed in thread-based programs==, as the state the program needs is on the stack of the thread.
|
||||||
hl-page:: 438
|
hl-page:: 438
|
||||||
ls-type:: annotation
|
ls-type:: annotation
|
||||||
id:: 6436a3d9-ee29-4378-af79-4efc770cc209
|
id:: 6436a3d9-ee29-4378-af79-4efc770cc209
|
||||||
@ -846,3 +752,18 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
|
|||||||
id:: 6436a485-7a70-4974-93d2-9e11b010a948
|
id:: 6436a485-7a70-4974-93d2-9e11b010a948
|
||||||
hl-color:: yellow
|
hl-color:: yellow
|
||||||
- Messy code base due to complicated asynchronous logic
|
- Messy code base due to complicated asynchronous logic
|
||||||
|
- obstinate 固执的;棘手的;难以去除的;
|
||||||
|
hl-page:: 448
|
||||||
|
ls-type:: annotation
|
||||||
|
id:: 6436ca1f-f4e7-431e-9620-be7764825acd
|
||||||
|
hl-color:: green
|
||||||
|
- pickle 泡菜;腌菜
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 448
|
||||||
|
hl-color:: green
|
||||||
|
id:: 6436caa1-6fe0-4de8-9ad4-2a057960fc1a
|
||||||
|
- System Architecture
|
||||||
|
ls-type:: annotation
|
||||||
|
hl-page:: 450
|
||||||
|
hl-color:: yellow
|
||||||
|
id:: 6436cc2e-b1af-4555-9d1d-808e6de120b1
|
||||||
Loading…
Reference in New Issue
Block a user