:first-child { margin-top: 0px; }
.markdown-preview:not([data-use-github-style]) h1, .markdown-preview:not([data-use-github-style]) h2, .markdown-preview:not([data-use-github-style]) h3, .markdown-preview:not([data-use-github-style]) h4, .markdown-preview:not([data-use-github-style]) h5, .markdown-preview:not([data-use-github-style]) h6 { line-height: 1.2; margin-top: 1.5em; margin-bottom: 0.5em; color: rgb(255, 255, 255); }
.markdown-preview:not([data-use-github-style]) h1 { font-size: 2.4em; font-weight: 300; }
.markdown-preview:not([data-use-github-style]) h2 { font-size: 1.8em; font-weight: 400; }
.markdown-preview:not([data-use-github-style]) h3 { font-size: 1.5em; font-weight: 500; }
.markdown-preview:not([data-use-github-style]) h4 { font-size: 1.2em; font-weight: 600; }
.markdown-preview:not([data-use-github-style]) h5 { font-size: 1.1em; font-weight: 600; }
.markdown-preview:not([data-use-github-style]) h6 { font-size: 1em; font-weight: 600; }
.markdown-preview:not([data-use-github-style]) strong { color: rgb(255, 255, 255); }
.markdown-preview:not([data-use-github-style]) del { color: rgb(124, 135, 156); }
.markdown-preview:not([data-use-github-style]) a, .markdown-preview:not([data-use-github-style]) a code { color: rgb(82, 139, 255); }
.markdown-preview:not([data-use-github-style]) img { max-width: 100%; }
.markdown-preview:not([data-use-github-style]) > p { margin-top: 0px; margin-bottom: 1.5em; }
.markdown-preview:not([data-use-github-style]) > ul, .markdown-preview:not([data-use-github-style]) > ol { margin-bottom: 1.5em; }
.markdown-preview:not([data-use-github-style]) blockquote { margin: 1.5em 0px; font-size: inherit; color: rgb(124, 135, 156); border-color: rgb(75, 83, 98); border-width: 4px; }
.markdown-preview:not([data-use-github-style]) hr { margin: 3em 0px; border-top: 2px dashed rgb(75, 83, 98); background: none; }
.markdown-preview:not([data-use-github-style]) table { margin: 1.5em 0px; }
.markdown-preview:not([data-use-github-style]) th { color: rgb(255, 255, 255); }
.markdown-preview:not([data-use-github-style]) th, .markdown-preview:not([data-use-github-style]) td { padding: 0.66em 1em; border: 1px solid rgb(75, 83, 98); }
.markdown-preview:not([data-use-github-style]) code { color: rgb(255, 255, 255); background-color: rgb(58, 63, 75); }
.markdown-preview:not([data-use-github-style]) pre.editor-colors { margin: 1.5em 0px; padding: 1em; font-size: 0.92em; border-radius: 3px; background-color: rgb(49, 54, 63); }
.markdown-preview:not([data-use-github-style]) kbd { color: rgb(255, 255, 255); border-width: 1px 1px 2px; border-style: solid; border-color: rgb(75, 83, 98) rgb(75, 83, 98) rgb(62, 68, 81); border-image: initial; background-color: rgb(58, 63, 75); }
.markdown-preview[data-use-github-style] { font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; line-height: 1.6; word-wrap: break-word; padding: 30px; font-size: 16px; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255); overflow: scroll; }
.markdown-preview[data-use-github-style] > :first-child { margin-top: 0px !important; }
.markdown-preview[data-use-github-style] > :last-child { margin-bottom: 0px !important; }
.markdown-preview[data-use-github-style] a:not([href]) { color: inherit; text-decoration: none; }
.markdown-preview[data-use-github-style] .absent { color: rgb(204, 0, 0); }
.markdown-preview[data-use-github-style] .anchor { position: absolute; top: 0px; left: 0px; display: block; padding-right: 6px; padding-left: 30px; margin-left: -30px; }
.markdown-preview[data-use-github-style] .anchor:focus { outline: none; }
.markdown-preview[data-use-github-style] h1, .markdown-preview[data-use-github-style] h2, .markdown-preview[data-use-github-style] h3, .markdown-preview[data-use-github-style] h4, .markdown-preview[data-use-github-style] h5, .markdown-preview[data-use-github-style] h6 { position: relative; margin-top: 1em; margin-bottom: 16px; font-weight: bold; line-height: 1.4; }
.markdown-preview[data-use-github-style] h1 .octicon-link, .markdown-preview[data-use-github-style] h2 .octicon-link, .markdown-preview[data-use-github-style] h3 .octicon-link, .markdown-preview[data-use-github-style] h4 .octicon-link, .markdown-preview[data-use-github-style] h5 .octicon-link, .markdown-preview[data-use-github-style] h6 .octicon-link { display: none; color: rgb(0, 0, 0); vertical-align: middle; }
.markdown-preview[data-use-github-style] h1:hover .anchor, .markdown-preview[data-use-github-style] h2:hover .anchor, .markdown-preview[data-use-github-style] h3:hover .anchor, .markdown-preview[data-use-github-style] h4:hover .anchor, .markdown-preview[data-use-github-style] h5:hover .anchor, .markdown-preview[data-use-github-style] h6:hover .anchor { padding-left: 8px; margin-left: -30px; text-decoration: none; }
.markdown-preview[data-use-github-style] h1:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h2:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h3:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h4:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h5:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h6:hover .anchor .octicon-link { display: inline-block; }
.markdown-preview[data-use-github-style] h1 tt, .markdown-preview[data-use-github-style] h2 tt, .markdown-preview[data-use-github-style] h3 tt, .markdown-preview[data-use-github-style] h4 tt, .markdown-preview[data-use-github-style] h5 tt, .markdown-preview[data-use-github-style] h6 tt, .markdown-preview[data-use-github-style] h1 code, .markdown-preview[data-use-github-style] h2 code, .markdown-preview[data-use-github-style] h3 code, .markdown-preview[data-use-github-style] h4 code, .markdown-preview[data-use-github-style] h5 code, .markdown-preview[data-use-github-style] h6 code { font-size: inherit; }
.markdown-preview[data-use-github-style] h1 { padding-bottom: 0.3em; font-size: 2.25em; line-height: 1.2; border-bottom: 1px solid rgb(238, 238, 238); }
.markdown-preview[data-use-github-style] h1 .anchor { line-height: 1; }
.markdown-preview[data-use-github-style] h2 { padding-bottom: 0.3em; font-size: 1.75em; line-height: 1.225; border-bottom: 1px solid rgb(238, 238, 238); }
.markdown-preview[data-use-github-style] h2 .anchor { line-height: 1; }
.markdown-preview[data-use-github-style] h3 { font-size: 1.5em; line-height: 1.43; }
.markdown-preview[data-use-github-style] h3 .anchor { line-height: 1.2; }
.markdown-preview[data-use-github-style] h4 { font-size: 1.25em; }
.markdown-preview[data-use-github-style] h4 .anchor { line-height: 1.2; }
.markdown-preview[data-use-github-style] h5 { font-size: 1em; }
.markdown-preview[data-use-github-style] h5 .anchor { line-height: 1.1; }
.markdown-preview[data-use-github-style] h6 { font-size: 1em; color: rgb(119, 119, 119); }
.markdown-preview[data-use-github-style] h6 .anchor { line-height: 1.1; }
.markdown-preview[data-use-github-style] p, .markdown-preview[data-use-github-style] blockquote, .markdown-preview[data-use-github-style] ul, .markdown-preview[data-use-github-style] ol, .markdown-preview[data-use-github-style] dl, .markdown-preview[data-use-github-style] table, .markdown-preview[data-use-github-style] pre { margin-top: 0px; margin-bottom: 16px; }
.markdown-preview[data-use-github-style] hr { height: 4px; padding: 0px; margin: 16px 0px; background-color: rgb(231, 231, 231); border: 0px none; }
.markdown-preview[data-use-github-style] ul, .markdown-preview[data-use-github-style] ol { padding-left: 2em; }
.markdown-preview[data-use-github-style] ul.no-list, .markdown-preview[data-use-github-style] ol.no-list { padding: 0px; list-style-type: none; }
.markdown-preview[data-use-github-style] ul ul, .markdown-preview[data-use-github-style] ul ol, .markdown-preview[data-use-github-style] ol ol, .markdown-preview[data-use-github-style] ol ul { margin-top: 0px; margin-bottom: 0px; }
.markdown-preview[data-use-github-style] li > p { margin-top: 16px; }
.markdown-preview[data-use-github-style] dl { padding: 0px; }
.markdown-preview[data-use-github-style] dl dt { padding: 0px; margin-top: 16px; font-size: 1em; font-style: italic; font-weight: bold; }
.markdown-preview[data-use-github-style] dl dd { padding: 0px 16px; margin-bottom: 16px; }
.markdown-preview[data-use-github-style] blockquote { padding: 0px 15px; color: rgb(119, 119, 119); border-left: 4px solid rgb(221, 221, 221); }
.markdown-preview[data-use-github-style] blockquote > :first-child { margin-top: 0px; }
.markdown-preview[data-use-github-style] blockquote > :last-child { margin-bottom: 0px; }
.markdown-preview[data-use-github-style] table { display: block; width: 100%; overflow: auto; word-break: keep-all; }
.markdown-preview[data-use-github-style] table th { font-weight: bold; }
.markdown-preview[data-use-github-style] table th, .markdown-preview[data-use-github-style] table td { padding: 6px 13px; border: 1px solid rgb(221, 221, 221); }
.markdown-preview[data-use-github-style] table tr { background-color: rgb(255, 255, 255); border-top: 1px solid rgb(204, 204, 204); }
.markdown-preview[data-use-github-style] table tr:nth-child(2n) { background-color: rgb(248, 248, 248); }
.markdown-preview[data-use-github-style] img { max-width: 100%; box-sizing: border-box; }
.markdown-preview[data-use-github-style] .emoji { max-width: none; }
.markdown-preview[data-use-github-style] span.frame { display: block; overflow: hidden; }
.markdown-preview[data-use-github-style] span.frame > span { display: block; float: left; width: auto; padding: 7px; margin: 13px 0px 0px; overflow: hidden; border: 1px solid rgb(221, 221, 221); }
.markdown-preview[data-use-github-style] span.frame span img { display: block; float: left; }
.markdown-preview[data-use-github-style] span.frame span span { display: block; padding: 5px 0px 0px; clear: both; color: rgb(51, 51, 51); }
.markdown-preview[data-use-github-style] span.align-center { display: block; overflow: hidden; clear: both; }
.markdown-preview[data-use-github-style] span.align-center > span { display: block; margin: 13px auto 0px; overflow: hidden; text-align: center; }
.markdown-preview[data-use-github-style] span.align-center span img { margin: 0px auto; text-align: center; }
.markdown-preview[data-use-github-style] span.align-right { display: block; overflow: hidden; clear: both; }
.markdown-preview[data-use-github-style] span.align-right > span { display: block; margin: 13px 0px 0px; overflow: hidden; text-align: right; }
.markdown-preview[data-use-github-style] span.align-right span img { margin: 0px; text-align: right; }
.markdown-preview[data-use-github-style] span.float-left { display: block; float: left; margin-right: 13px; overflow: hidden; }
.markdown-preview[data-use-github-style] span.float-left span { margin: 13px 0px 0px; }
.markdown-preview[data-use-github-style] span.float-right { display: block; float: right; margin-left: 13px; overflow: hidden; }
.markdown-preview[data-use-github-style] span.float-right > span { display: block; margin: 13px auto 0px; overflow: hidden; text-align: right; }
.markdown-preview[data-use-github-style] code, .markdown-preview[data-use-github-style] tt { padding: 0.2em 0px; margin: 0px; font-size: 85%; background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; }
.markdown-preview[data-use-github-style] code::before, .markdown-preview[data-use-github-style] tt::before, .markdown-preview[data-use-github-style] code::after, .markdown-preview[data-use-github-style] tt::after { letter-spacing: -0.2em; content: " "; }
.markdown-preview[data-use-github-style] code br, .markdown-preview[data-use-github-style] tt br { display: none; }
.markdown-preview[data-use-github-style] del code { text-decoration: inherit; }
.markdown-preview[data-use-github-style] pre > code { padding: 0px; margin: 0px; font-size: 100%; word-break: normal; white-space: pre; background: transparent; border: 0px; }
.markdown-preview[data-use-github-style] .highlight { margin-bottom: 16px; }
.markdown-preview[data-use-github-style] .highlight pre, .markdown-preview[data-use-github-style] pre { padding: 16px; overflow: auto; font-size: 85%; line-height: 1.45; background-color: rgb(247, 247, 247); border-radius: 3px; }
.markdown-preview[data-use-github-style] .highlight pre { margin-bottom: 0px; word-break: normal; }
.markdown-preview[data-use-github-style] pre { word-wrap: normal; }
.markdown-preview[data-use-github-style] pre code, .markdown-preview[data-use-github-style] pre tt { display: inline; max-width: initial; padding: 0px; margin: 0px; overflow: initial; line-height: inherit; word-wrap: normal; background-color: transparent; border: 0px; }
.markdown-preview[data-use-github-style] pre code::before, .markdown-preview[data-use-github-style] pre tt::before, .markdown-preview[data-use-github-style] pre code::after, .markdown-preview[data-use-github-style] pre tt::after { content: normal; }
.markdown-preview[data-use-github-style] kbd { display: inline-block; padding: 3px 5px; font-size: 11px; line-height: 10px; color: rgb(85, 85, 85); vertical-align: middle; background-color: rgb(252, 252, 252); border-width: 1px; border-style: solid; border-color: rgb(204, 204, 204) rgb(204, 204, 204) rgb(187, 187, 187); border-image: initial; border-radius: 3px; box-shadow: rgb(187, 187, 187) 0px -1px 0px inset; }
.markdown-preview[data-use-github-style] a { color: rgb(51, 122, 183); }
.markdown-preview[data-use-github-style] code { color: inherit; }
.markdown-preview[data-use-github-style] pre.editor-colors { padding: 0.8em 1em; margin-bottom: 1em; font-size: 0.85em; border-radius: 4px; overflow: auto; }
.scrollbars-visible-always .markdown-preview pre.editor-colors .vertical-scrollbar, .scrollbars-visible-always .markdown-preview pre.editor-colors .horizontal-scrollbar { visibility: hidden; }
.scrollbars-visible-always .markdown-preview pre.editor-colors:hover .vertical-scrollbar, .scrollbars-visible-always .markdown-preview pre.editor-colors:hover .horizontal-scrollbar { visibility: visible; }
.markdown-preview .task-list-item-checkbox { position: absolute; margin: 0.25em 0px 0px -1.4em; }
.bracket-matcher .region {
border-bottom: 1px dotted lime;
position: absolute;
}

.spell-check-misspelling .region {
border-bottom: 2px dotted rgba(255, 51, 51, 0.75);
}
.spell-check-corrections {
width: 25em !important;
}

pre.editor-colors {
background-color: #282c34;
color: #abb2bf;
}
pre.editor-colors .line.cursor-line {
background-color: rgba(153, 187, 255, 0.04);
}
pre.editor-colors .invisible {
color: #abb2bf;
}
pre.editor-colors .cursor {
border-left: 2px solid #528bff;
}
pre.editor-colors .selection .region {
background-color: #3e4451;
}
pre.editor-colors .bracket-matcher .region {
border-bottom: 1px solid #528bff;
box-sizing: border-box;
}
pre.editor-colors .invisible-character {
color: rgba(171, 178, 191, 0.15);
}
pre.editor-colors .indent-guide {
color: rgba(171, 178, 191, 0.15);
}
pre.editor-colors .wrap-guide {
background-color: rgba(171, 178, 191, 0.15);
}
pre.editor-colors .find-result .region.region.region,
pre.editor-colors .current-result .region.region.region {
border-radius: 2px;
background-color: rgba(82, 139, 255, 0.24);
transition: border-color 0.4s;
}
pre.editor-colors .find-result .region.region.region {
border: 2px solid transparent;
}
pre.editor-colors .current-result .region.region.region {
border: 2px solid #528bff;
transition-duration: .1s;
}
pre.editor-colors .gutter .line-number {
color: #636d83;
-webkit-font-smoothing: antialiased;
}
pre.editor-colors .gutter .line-number.cursor-line {
color: #abb2bf;
background-color: #2c313a;
}
pre.editor-colors .gutter .line-number.cursor-line-no-selection {
background-color: transparent;
}
pre.editor-colors .gutter .line-number .icon-right {
color: #abb2bf;
}
pre.editor-colors .gutter:not(.git-diff-icon) .line-number.git-line-removed.git-line-removed::before {
bottom: -3px;
}
pre.editor-colors .gutter:not(.git-diff-icon) .line-number.git-line-removed::after {
content: "";
position: absolute;
left: 0px;
bottom: 0px;
width: 25px;
border-bottom: 1px dotted rgba(224, 82, 82, 0.5);
pointer-events: none;
}
pre.editor-colors .gutter .line-number.folded,
pre.editor-colors .gutter .line-number:after,
pre.editor-colors .fold-marker:after {
color: #abb2bf;
}
.syntax--comment {
color: #5c6370;
font-style: italic;
}
.syntax--comment .syntax--markup.syntax--link {
color: #5c6370;
}
.syntax--entity.syntax--name.syntax--type {
color: #e5c07b;
}
.syntax--entity.syntax--other.syntax--inherited-class {
color: #98c379;
}
.syntax--keyword {
color: #c678dd;
}
.syntax--keyword.syntax--control {
color: #c678dd;
}
.syntax--keyword.syntax--operator {
color: #abb2bf;
}
.syntax--keyword.syntax--other.syntax--special-method {
color: #61afef;
}
.syntax--keyword.syntax--other.syntax--unit {
color: #d19a66;
}
.syntax--storage {
color: #c678dd;
}
.syntax--storage.syntax--type.syntax--annotation,
.syntax--storage.syntax--type.syntax--primitive {
color: #c678dd;
}
.syntax--storage.syntax--modifier.syntax--package,
.syntax--storage.syntax--modifier.syntax--import {
color: #abb2bf;
}
.syntax--constant {
color: #d19a66;
}
.syntax--constant.syntax--variable {
color: #d19a66;
}
.syntax--constant.syntax--character.syntax--escape {
color: #56b6c2;
}
.syntax--constant.syntax--numeric {
color: #d19a66;
}
.syntax--constant.syntax--other.syntax--color {
color: #56b6c2;
}
.syntax--constant.syntax--other.syntax--symbol {
color: #56b6c2;
}
.syntax--variable {
color: #e06c75;
}
.syntax--variable.syntax--interpolation {
color: #be5046;
}
.syntax--variable.syntax--parameter {
color: #abb2bf;
}
.syntax--string {
color: #98c379;
}
.syntax--string.syntax--regexp {
color: #56b6c2;
}
.syntax--string.syntax--regexp .syntax--source.syntax--ruby.syntax--embedded {
color: #e5c07b;
}
.syntax--string.syntax--other.syntax--link {
color: #e06c75;
}
.syntax--punctuation.syntax--definition.syntax--comment {
color: #5c6370;
}
.syntax--punctuation.syntax--definition.syntax--method-parameters,
.syntax--punctuation.syntax--definition.syntax--function-parameters,
.syntax--punctuation.syntax--definition.syntax--parameters,
.syntax--punctuation.syntax--definition.syntax--separator,
.syntax--punctuation.syntax--definition.syntax--seperator,
.syntax--punctuation.syntax--definition.syntax--array {
color: #abb2bf;
}
.syntax--punctuation.syntax--definition.syntax--heading,
.syntax--punctuation.syntax--definition.syntax--identity {
color: #61afef;
}
.syntax--punctuation.syntax--definition.syntax--bold {
color: #e5c07b;
font-weight: bold;
}
.syntax--punctuation.syntax--definition.syntax--italic {
color: #c678dd;
font-style: italic;
}
.syntax--punctuation.syntax--section.syntax--embedded {
color: #be5046;
}
.syntax--punctuation.syntax--section.syntax--method,
.syntax--punctuation.syntax--section.syntax--class,
.syntax--punctuation.syntax--section.syntax--inner-class {
color: #abb2bf;
}
.syntax--support.syntax--class {
color: #e5c07b;
}
.syntax--support.syntax--type {
color: #56b6c2;
}
.syntax--support.syntax--function {
color: #56b6c2;
}
.syntax--support.syntax--function.syntax--any-method {
color: #61afef;
}
.syntax--entity.syntax--name.syntax--function {
color: #61afef;
}
.syntax--entity.syntax--name.syntax--class,
.syntax--entity.syntax--name.syntax--type.syntax--class {
color: #e5c07b;
}
.syntax--entity.syntax--name.syntax--section {
color: #61afef;
}
.syntax--entity.syntax--name.syntax--tag {
color: #e06c75;
}
.syntax--entity.syntax--other.syntax--attribute-name {
color: #d19a66;
}
.syntax--entity.syntax--other.syntax--attribute-name.syntax--id {
color: #61afef;
}
.syntax--meta.syntax--class {
color: #e5c07b;
}
.syntax--meta.syntax--class.syntax--body {
color: #abb2bf;
}
.syntax--meta.syntax--method-call,
.syntax--meta.syntax--method {
color: #abb2bf;
}
.syntax--meta.syntax--definition.syntax--variable {
color: #e06c75;
}
.syntax--meta.syntax--link {
color: #d19a66;
}
.syntax--meta.syntax--require {
color: #61afef;
}
.syntax--meta.syntax--selector {
color: #c678dd;
}
.syntax--meta.syntax--separator {
background-color: #373b41;
color: #abb2bf;
}
.syntax--meta.syntax--tag {
color: #abb2bf;
}
.syntax--underline {
text-decoration: underline;
}
.syntax--none {
color: #abb2bf;
}
.syntax--invalid.syntax--deprecated {
color: #523d14 !important;
background-color: #e0c285 !important;
}
.syntax--invalid.syntax--illegal {
color: white !important;
background-color: #e05252 !important;
}
.syntax--markup.syntax--bold {
color: #d19a66;
font-weight: bold;
}
.syntax--markup.syntax--changed {
color: #c678dd;
}
.syntax--markup.syntax--deleted {
color: #e06c75;
}
.syntax--markup.syntax--italic {
color: #c678dd;
font-style: italic;
}
.syntax--markup.syntax--heading {
color: #e06c75;
}
.syntax--markup.syntax--heading .syntax--punctuation.syntax--definition.syntax--heading {
color: #61afef;
}
.syntax--markup.syntax--link {
color: #56b6c2;
}
.syntax--markup.syntax--inserted {
color: #98c379;
}
.syntax--markup.syntax--quote {
color: #d19a66;
}
.syntax--markup.syntax--raw {
color: #98c379;
}
.syntax--source.syntax--c .syntax--keyword.syntax--operator {
color: #c678dd;
}
.syntax--source.syntax--cpp .syntax--keyword.syntax--operator {
color: #c678dd;
}
.syntax--source.syntax--cs .syntax--keyword.syntax--operator {
color: #c678dd;
}
.syntax--source.syntax--css .syntax--property-name,
.syntax--source.syntax--css .syntax--property-value {
color: #828997;
}
.syntax--source.syntax--css .syntax--property-name.syntax--support,
.syntax--source.syntax--css .syntax--property-value.syntax--support {
color: #abb2bf;
}
.syntax--source.syntax--elixir .syntax--source.syntax--embedded.syntax--source {
color: #abb2bf;
}
.syntax--source.syntax--elixir .syntax--constant.syntax--language,
.syntax--source.syntax--elixir .syntax--constant.syntax--numeric,
.syntax--source.syntax--elixir .syntax--constant.syntax--definition {
color: #61afef;
}
.syntax--source.syntax--elixir .syntax--variable.syntax--definition,
.syntax--source.syntax--elixir .syntax--variable.syntax--anonymous {
color: #c678dd;
}
.syntax--source.syntax--elixir .syntax--quoted {
color: #98c379;
}
.syntax--source.syntax--elixir .syntax--keyword.syntax--special-method,
.syntax--source.syntax--elixir .syntax--embedded.syntax--section,
.syntax--source.syntax--elixir .syntax--embedded.syntax--source.syntax--empty {
color: #e06c75;
}
.syntax--source.syntax--elixir .syntax--readwrite.syntax--module .syntax--punctuation {
color: #e06c75;
}
.syntax--source.syntax--elixir .syntax--regexp.syntax--section,
.syntax--source.syntax--elixir .syntax--regexp.syntax--string {
color: #be5046;
}
.syntax--source.syntax--elixir .syntax--separator,
.syntax--source.syntax--elixir .syntax--keyword.syntax--operator {
color: #d19a66;
}
.syntax--source.syntax--elixir .syntax--variable.syntax--constant {
color: #e5c07b;
}
.syntax--source.syntax--elixir .syntax--array,
.syntax--source.syntax--elixir .syntax--scope,
.syntax--source.syntax--elixir .syntax--section {
color: #828997;
}
.syntax--source.syntax--gfm .syntax--markup {
-webkit-font-smoothing: auto;
}
.syntax--source.syntax--gfm .syntax--link .syntax--entity {
color: #61afef;
}
.syntax--source.syntax--go .syntax--storage.syntax--type.syntax--string {
color: #c678dd;
}
.syntax--source.syntax--ini .syntax--keyword.syntax--other.syntax--definition.syntax--ini {
color: #e06c75;
}
.syntax--source.syntax--java .syntax--storage.syntax--modifier.syntax--import {
color: #e5c07b;
}
.syntax--source.syntax--java .syntax--storage.syntax--type {
color: #e5c07b;
}
.syntax--source.syntax--java .syntax--keyword.syntax--operator.syntax--instanceof {
color: #c678dd;
}
.syntax--source.syntax--java-properties .syntax--meta.syntax--key-pair {
color: #e06c75;
}
.syntax--source.syntax--java-properties .syntax--meta.syntax--key-pair > .syntax--punctuation {
color: #abb2bf;
}
.syntax--source.syntax--js .syntax--keyword.syntax--operator {
color: #56b6c2;
}
.syntax--source.syntax--js .syntax--keyword.syntax--operator.syntax--delete,
.syntax--source.syntax--js .syntax--keyword.syntax--operator.syntax--in,
.syntax--source.syntax--js .syntax--keyword.syntax--operator.syntax--of,
.syntax--source.syntax--js .syntax--keyword.syntax--operator.syntax--instanceof,
.syntax--source.syntax--js .syntax--keyword.syntax--operator.syntax--new,
.syntax--source.syntax--js .syntax--keyword.syntax--operator.syntax--typeof,
.syntax--source.syntax--js .syntax--keyword.syntax--operator.syntax--void {
color: #c678dd;
}
.syntax--source.syntax--json .syntax--meta.syntax--structure.syntax--dictionary.syntax--json > .syntax--string.syntax--quoted.syntax--json {
color: #e06c75;
}
.syntax--source.syntax--json .syntax--meta.syntax--structure.syntax--dictionary.syntax--json > .syntax--string.syntax--quoted.syntax--json > .syntax--punctuation.syntax--string {
color: #e06c75;
}
.syntax--source.syntax--json .syntax--meta.syntax--structure.syntax--dictionary.syntax--json > .syntax--value.syntax--json > .syntax--string.syntax--quoted.syntax--json,
.syntax--source.syntax--json .syntax--meta.syntax--structure.syntax--array.syntax--json > .syntax--value.syntax--json > .syntax--string.syntax--quoted.syntax--json,
.syntax--source.syntax--json .syntax--meta.syntax--structure.syntax--dictionary.syntax--json > .syntax--value.syntax--json > .syntax--string.syntax--quoted.syntax--json > .syntax--punctuation,
.syntax--source.syntax--json .syntax--meta.syntax--structure.syntax--array.syntax--json > .syntax--value.syntax--json > .syntax--string.syntax--quoted.syntax--json > .syntax--punctuation {
color: #98c379;
}
.syntax--source.syntax--json .syntax--meta.syntax--structure.syntax--dictionary.syntax--json > .syntax--constant.syntax--language.syntax--json,
.syntax--source.syntax--json .syntax--meta.syntax--structure.syntax--array.syntax--json > .syntax--constant.syntax--language.syntax--json {
color: #56b6c2;
}
.syntax--source.syntax--ruby .syntax--constant.syntax--other.syntax--symbol > .syntax--punctuation {
color: inherit;
}
.syntax--source.syntax--python .syntax--keyword.syntax--operator.syntax--logical.syntax--python {
color: #c678dd;
}
.syntax--source.syntax--python .syntax--variable.syntax--parameter {
color: #d19a66;
}
-->

本文的主要参考资料为 BOOST线程完全攻略 - 基础篇 这里主要是对其中的例程进行学习,相关说明还请参考原文。

1 创建一个简单的多线程示例

在boost中创建一个 boost::thread 类的对象就代表一个可执行的线程。该类的定义在boost/thread/thread.hpp中,最简单的使用方式是直接传递给其一个函数对象或函数指针,创建thread后会自动新建一个线程并立刻执行函数对象或指针的()操作。boost::thread类提供了join方法来等待线程对象的结束。
下面这个示例演示了线程的基本创建方法,并且主程序在等待线程结束之后再退出,为了方便观察这里还加上一个额外的等待语句。

#include <boost/thread/thread.hpp>
#include <iostream>
void hello()
{
        std::cout <<
        "Hello world, I'm a thread!"
        << std::endl;
}
int main(int argc, char* argv[])
{
        boost::thread thrd(&hello);
        thrd.join();
        int i;
        std::cin>>i;
        return 0;
}

2 临界资源的互斥访问

所谓的临界资源就是那些每次只允许一个线程访问的资源,硬件的临界资源有打印机等,软件的临界资源有缓冲区等。标准输出流中的缓冲区就是一个临界资源,对应的线程中访问临界资源的代码我们就称之为临界区,如cout<<"Hello!"<<endl;这段代码就是临界区,它向标准输出流的缓冲区中写入一段字符并用endl来刷新缓冲区。很显然如果有多个线程都同时向标准输出设备的缓冲区中写数据,那么打印出来的结果有可能是无效的。这时候就需要互斥锁来保证临界资源的互斥访问了。一般在访问临界区之前都要上锁,退出临界区后再解锁。
互斥锁根据所需的功能不同,执行效率有所区别。boost::mutex就是一种简单高效的互斥锁类型。为了保证互斥锁总是能够解锁,boost将加锁和解锁的动作分别封装到一个类的构造函数和析构函数中,由于类再离开其作用域或抛出异常后总是能执行其析构函数,所有不会出现死锁的事情,这个封装的类就是boost::mutex::scoped_lock。互斥锁类定义在boost/thread/mutex.hpp中。下例就是一个对cout互斥访问的例子:

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
 
class MyCout
{
private:
    int Id;
    static boost::mutex IoMutex;
public:
    MyCout(int id):Id(id){}
    void operator()()
    {
        for(int i = 0;i < 5;++i)
        {
            boost::mutex::scoped_lock lock(IoMutex);
 
            std::cout<<"线程"<<Id<<": "<<i<<std::endl;
        }
    }
};
 
boost::mutex MyCout::IoMutex;
 
int main(int argc,char* argv[])
{
    boost::thread thrd1(MyCout(1));
    boost::thread thrd2(MyCout(2));
    thrd1.join();
    thrd2.join();
    int i;
    std::cin>>i;
    return 0;
}

上例定义的函数对象MyCout中有两个成员变量,一个是用来表示线程的ID,另一个为静态成员的互斥锁用来保证所有通过该函数类所产生的函数对象都会互斥的使用临界资源。注意静态成员必须要在类的外部进行定义,在类内部只是进行了声明。

3 使用boost::bind给函数绑定数据

前面使用函数对象来执行线程,使得其不但能保存程序而且还能保存相关的数据。我们使用boost::bind将函数和数据绑定到一起也能实现相同的功能,该类的定义位于boost/bind.hpp之中。

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
 
boost::mutex IoMutex;
 
void MyCout(int id)
{
    for(int i = 0;i < 5;++i)
    {
        boost::mutex::scoped_lock lock(IoMutex);
        std::cout<<"线程"<<id<<": "<<i<<std::endl;
    }
}
 
int main(int argc,char* argv[])
{
    boost::thread thrd1(boost::bind(&MyCout,1));
    boost::thread thrd2(boost::bind(&MyCout,2));
    thrd1.join();
    thrd2.join();
    int i;
    std::cin>>i;
    return 0;
}

4 条件变量

有时候仅仅是保证临界资源的互斥方式是不能满足我们的要求的,比如对于一个缓冲区操作的线程,除了保证缓冲区的互斥访问之外,对于写入的线程还必须要保证缓冲区不满,对于从缓冲区中读取的线程还必须要保证缓冲区非空。当然我们可以使用一个变量来判断缓冲区是否可操作,对于读取缓冲区我们可用判断DataNum != 0来进行操作。但是这样做会增加程序的判断逻辑使程序结构变得复杂。boost提供了这种等待条件变量的机制。在代码(GetData线程)进入临界区前,首先锁住互斥变量,然后检验临界资源是否可用,如果不可用(缓冲区为空),那么线程就会等待(调用wait方法),等待的过程中会解锁互斥量以便其他线程能够运行以改变临界资源的状态,同时也会阻塞当前线程防止当前线程和其他线程同时访问临界区。如果某个线程(PutData线程)改变了临界资源使其对该线程来说可用了,那么在那个线程(PutData线程)运行完毕后应该调用notify_one来取消wait方法阻塞的一个线程,在从wait方法返回之前,wait会再次给互斥量加锁。
下面这个示例是一个使用条件变量的例子,其中全局互斥量IoMutex和之前的例子一样,使用来保证标准输出流的缓冲区进行互斥访问。而类中的互斥量就是用来保证类中的方法是互斥的使用的。条件变量有多种这里我们使用的是condition,这个类型是condition_variable_any的别名,定义在boost/condition.hpp中。

#include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
 
typedef boost::mutex::scoped_lock scoped_lock;
 
boost::mutex IoMutex;
const int BufferSize = 10;
const int Iters = 100;
 
 
class Buffer
{
public:
    Buffer():P(0),C(0),DataNum(0){}
 
    void Write(int m)
    {
        scoped_lock lock(Mutex);
        if(DataNum == BufferSize)
        {
            {
                scoped_lock ioLock(IoMutex);
                std::cout<<"Buffer is full.Waiting..."<<std::endl;
            }
            while(DataNum == BufferSize)
                Cond.wait(lock);
        }
        Buf[P] = m;
        P = (P+1)%BufferSize;    //队列的入口
        ++DataNum;
        Cond.notify_one();
    }
 
    int Read()
    {
        scoped_lock lock(Mutex);
        if(DataNum == 0)
        {
            {
                scoped_lock ioLock(IoMutex);
                std::cout<<"Buffer is empty.Waiting..."<<std::endl;
            }
            while(DataNum == 0)
                Cond.wait(lock);
        }
        int i = Buf[C];
        C= (C+1)%BufferSize;    //队列的出口
        --DataNum;
        Cond.notify_one();
        return i;
    }
private:
    int Buf[BufferSize];
    int P;
    int C;
    int DataNum;
    boost::mutex Mutex;
    boost::condition Cond;
};
 
Buffer buf;
 
void Writer()
{
    for(int n = 0;n < Iters;++n)
    {
        {
            scoped_lock ioLock(IoMutex);
            std::cout<<"sending:"<<n<<std::endl;
        }
        buf.Write(n);
    }
}
 
void Reader()
{
    for(int i = 0;i < Iters;++i)
    {
        int n = buf.Read();
        {
            scoped_lock ioLock(IoMutex);
            std::cout<<"received:"<<n<<std::endl;
        }
    }
}
 
int main(int argc,char* argv[])
{
    boost::thread thrd1(&Writer);
    boost::thread thrd2(&Reader);
    int i;
    std::cin>>i;
    return 0;
}

5 线程局部存储

一般对于含有静态变量或者返回指向静态数据的指针的函数是不可重入的,即同时只能有一个线程可以使用该函数,如std::strtok就是不可重入的函数。Boost线程库提供了智能指针boost::thread_spacific_ptr可以保证对于不同的线程这个指针指向的数据是相互独立的。由于不同线程指向的数据不同,所以每一个线程在使用这个指针之前都必须要对其进行赋值。该指针的定义位于boost/thread/tss.hpp中,下面是一个使用示例:

#include <boost/thread/thread.hpp>
#include <boost/thread/tss.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
 
boost::mutex IoMutex;
boost::thread_specific_ptr<int> Ptr;        //指向int的智能指针
 
struct MyCout
{
    MyCout(int id):Id(id){}
 
    void operator()()
    {
        if(Ptr.get() == 0)
            Ptr.reset(new int(0));        //每个线程使用前都需要给指针赋值
        for(int i = 0;i < 5;++i)
        {
            (*Ptr)++;
            boost::mutex::scoped_lock IoLock(IoMutex);
            std::cout<<Id<<": "<<*Ptr<<std::endl;
        }
    }
    int Id;
};
 
int main(int argc,char* argv[])
{
    boost::thread thrd1(MyCout(1));
    boost::thread thrd2(MyCout(2));
    int i;
    std::cin>>i;
    return 0;
}
 
# 6 仅运行一次的例程  
 
多线程编程中还存在一个问题,那就是我们有一个函数可能被很多个线程调用,但是我们却只想它执行一次。即如果该函数已经执行过了那么再次调用时并不会执行。我们可用通过手动添加全局标志位的方式来实现。也可以使用`boost::call_once`来实现。`call_once`同样需要借助于一个全局标志位`boost::once_flag`并且需要使用宏`BOOST_ONCE_INIT`来初始化这个标志位。函数和宏定义在`boost/thread/once/hpp`中,下面是一个使用示例:  
 
```c++
#include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp>
#include <iostream>
 
int GlobalVal = 0;        //只想初始化这个变量一次
boost::once_flag Flag= BOOST_ONCE_INIT;
 
void Init()
{
    ++GlobalVal;
}
 
void thread()
{
    boost::call_once(&Init,Flag);
}
 
int main(int argc,char* argv[])
{
    boost::thread thrd1(&thread);
    boost::thread thrd2(&thread);
    thrd1.join();
    thrd2.join();
    std::cout<<GlobalVal<<std::endl;
 
    int i;
    std::cin>>i;
    return 0;
}

上面程序执行完毕后,GlobalVal值为1,说明确实只执行了一遍初始化函数。

参考文章:

关于在类中创建线程的多种方式可以参考:
boost::thread线程创建方式总结

boost多线程入门介绍的更多相关文章

  1. .NET 4 并行(多核)编程系列之一入门介绍

    .NET 4 并行(多核)编程系列之一入门介绍 本系列文章将会对.NET 4中的并行编程技术(也称之为多核编程技术)以及应用作全面的介绍. 本篇文章的议题如下:  1. 并行编程和多线程编程的区别.  ...

  2. Linux入门介绍

    Linux入门介绍 一.Linux 初步介绍 Linux的优点 免费的,开源的 支持多线程,多用户 安全性好 对内存和文件管理优越 系统稳定 消耗资源少 Linux的缺点 操作相对困难 一些专业软件以 ...

  3. Apache shiro集群实现 (一) shiro入门介绍

    近期在ITOO项目中研究使用Apache shiro集群中要解决的两个问题,一个是Session的共享问题,一个是授权信息的cache共享问题,官网上给的例子是Ehcache的实现,在配置说明上不算很 ...

  4. java多线程入门学习(一)

    java多线程入门学习(一) 一.java多线程之前 进程:每一个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销.一个进程包括1--n个线程.     线程:同一类线程共享代码 ...

  5. Java多线程学习(一)Java多线程入门

    转载请备注地址:https://blog.csdn.net/qq_34337272/article/details/79640870 系列文章传送门: Java多线程学习(一)Java多线程入门 Ja ...

  6. JavaSE_多线程入门 线程安全 死锁 状态 通讯 线程池

    1 多线程入门 1.1 多线程相关的概念 并发与并行 并行:在同一时刻,有多个任务在多个CPU上同时执行. 并发:在同一时刻,有多个任务在单个CPU上交替执行. 进程与线程 进程:就是操作系统中正在运 ...

  7. iOS开发多线程篇—多线程简单介绍

    iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcod ...

  8. C# BackgroundWorker组件学习入门介绍

    C# BackgroundWorker组件学习入门介绍 一个程序中需要进行大量的运算,并且需要在运算过程中支持用户一定的交互,为了获得更好的用户体验,使用BackgroundWorker来完成这一功能 ...

  9. 初识Hadoop入门介绍

    初识hadoop入门介绍 Hadoop一直是我想学习的技术,正巧最近项目组要做电子商城,我就开始研究Hadoop,虽然最后鉴定Hadoop不适用我们的项目,但是我会继续研究下去,技多不压身. < ...

随机推荐

  1. Redlock(redis分布式锁)原理分析

    Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁: 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击) ...

  2. win10环境下适应pip安装autobahn提示认证失败的问题

    工作需要看一下websocket的东西,然后使用autobahn三方,但是使用pip install安装怎么也安装不上,问了很多网站,都说的升级pip,可是每一个鸡巴管用的,不过还是谢谢他们,现在我只 ...

  3. python 平衡二叉树实现

    平衡二叉树: 在上一节二叉树的基础上我们实现,如何将生成平衡的二叉树 所谓平衡二叉树: 我自己定义就是:任何一个节点的左高度和右高度的差的绝对值都小于2 如图所示,此时a的左高度等于3,有高度等于1, ...

  4. IntelliJ IDEA spring boot 远程Ddbug调试

    一.idea配置 1.在idea中点击右上角的 "Edit Configurations" 2.点击+,选择Remote 3.在Name处为此次Dbug起个名字,在Host添加测试 ...

  5. 浅谈Android之Activity生命周期

     Activity作为四大组件之一,出现的频率相当高,基本上我们在android的各个地方都能看见它的踪影,因此深入了解Activity,对于开发高质量应用程序是很有帮助的.今天我们就来详细地聊聊Ac ...

  6. LeetCode 102. Binary Tree Level Order Traversal 二叉树的层次遍历 C++

    Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, ...

  7. php laravel+nginx 除了根目录都报404 解决

    在nginx的配置文件加 location / { try_files $uri $uri/ /index.php?$query_string; } 即可!!!!!!!

  8. JSTL的使用

    使用JSTL前的准备 想要使用JSTL,首先需要给工程导入JSTL的包(JSTL.jar和standard.jar). JSTL标签库 在JSTL中分为以下五个标签 核心标签 格式化标签 SQL标签 ...

  9. 侧脸生成正脸概论与精析(一)Global and Local Perception GAN

    侧脸生成正脸我一直很感兴趣,老早就想把这块理一理的.今天来给大家分享一篇去年的老文章,如果有不对的地方,请斧正. Beyond Face Rotation: Global and Local Perc ...

  10. 一条SQL语句执行得很慢的原因有哪些?

    说实话,这个问题可以涉及到 MySQL 的很多核心知识,可以扯出一大堆,就像要考你计算机网络的知识时,问你“输入URL回车之后,究竟发生了什么”一样,看看你能说出多少了. 之前腾讯面试的实话,也问到这 ...