OSTEP Chapterr 28

This commit is contained in:
ridethepig 2023-04-11 17:16:09 +08:00
parent e698da3c30
commit 36d188acfa
2 changed files with 967 additions and 11 deletions

View File

@ -486,5 +486,692 @@
:height 1296}),
:page 344},
:content {:text "test-and-set (or atomic exchange1) instruction"},
:properties {:color "yellow"}}
{:id #uuid "6434edd3-2a7b-4e11-af18-29854e628bc6",
:page 345,
:position {:bounding {:x1 491.1250305175781,
:y1 377.0089416503906,
:x2 658.8576049804688,
:y2 400.4375305175781,
:width 864,
:height 1296},
:rects ({:x1 491.1250305175781,
:y1 377.0089416503906,
:x2 658.8576049804688,
:y2 400.4375305175781,
:width 864,
:height 1296}),
:page 345},
:content {:text "Petersons algorithm"},
:properties {:color "yellow"}}
{:id #uuid "6434f523-44b7-40ab-8fea-528969c5acfd",
:page 347,
:position {:bounding {:x1 402.9370536804199,
:y1 274.72320556640625,
:x2 440.68061447143555,
:y2 292.4375,
:width 864,
:height 1296},
:rects ({:x1 402.9370536804199,
:y1 274.72320556640625,
:x2 440.68061447143555,
:y2 292.4375,
:width 864,
:height 1296}),
:page 347},
:content {:text "foil "},
:properties {:color "green"}}
{:id #uuid "6434f8ac-d762-40a4-abb0-2955c2c8b396",
:page 348,
:position {:bounding {:x1 203.03572463989258,
:y1 550.3303833007812,
:x2 358.456729888916,
:y2 573.7589569091797,
:width 864,
:height 1296},
:rects ({:x1 203.03572463989258,
:y1 550.3303833007812,
:x2 358.456729888916,
:y2 573.7589569091797,
:width 864,
:height 1296}),
:page 348},
:content {:text "compare-and-swap"},
:properties {:color "yellow"}}
{:id #uuid "6434fab0-08de-4f28-8d8e-f48f7e04aaaa",
:page 348,
:position {:bounding {:x1 0,
:y1 301.1428756713867,
:x2 746.9776916503906,
:y2 669.5536117553711,
:width 864,
:height 1296},
:rects ({:x1 0,
:y1 301.1428756713867,
:x2 0,
:y2 322.28572845458984,
:width 864,
:height 1296}
{:x1 0,
:y1 317.1428756713867,
:x2 0,
:y2 338.28572845458984,
:width 864,
:height 1296}
{:x1 528.7957763671875,
:y1 611.7679061889648,
:x2 745.6440734863281,
:y2 629.4822006225586,
:width 864,
:height 1296}
{:x1 171.89286422729492,
:y1 631.6964340209961,
:x2 746.9776916503906,
:y2 649.6250228881836,
:width 864,
:height 1296}
{:x1 171.89286422729492,
:y1 651.6250228881836,
:x2 731.2063903808594,
:y2 669.5536117553711,
:width 864,
:height 1296}),
:page 348},
:content {:text "est whether the value at the address specified by ptr is equal to expected; if so, update the memory location pointed to by ptr with the new value. If not, do nothing. "},
:properties {:color "yellow"}}
{:id #uuid "6434fb8c-2b3b-4d80-83fb-3b34da4dcd28",
:page 349,
:position {:bounding {:x1 333.7612075805664,
:y1 182.38393259048462,
:x2 382.13965606689453,
:y2 200.09822702407837,
:width 864,
:height 1296},
:rects ({:x1 333.7612075805664,
:y1 182.38393259048462,
:x2 382.13965606689453,
:y2 200.09822702407837,
:width 864,
:height 1296}),
:page 349},
:content {:text "delve "},
:properties {:color "green"}}
{:id #uuid "6434fde1-9d19-4381-805e-f2a972875dc2",
:page 349,
:position {:bounding {:x1 140.9732208251953,
:y1 353.53572845458984,
:x2 417.0097427368164,
:y2 376.9642868041992,
:width 864,
:height 1296},
:rects ({:x1 144.50000762939453,
:y1 353.53572845458984,
:x2 245.45536041259766,
:y2 376.9642868041992,
:width 864,
:height 1296}
{:x1 277.5178756713867,
:y1 353.53572845458984,
:x2 417.0097427368164,
:y2 376.9642868041992,
:width 864,
:height 1296}
{:x1 140.9732208251953,
:y1 355.1964340209961,
:x2 417.0097427368164,
:y2 373.1250228881836,
:width 864,
:height 1296}),
:page 349},
:content {:text " load-linked and store-conditional"},
:properties {:color "yellow"}}
{:id #uuid "6434fe1c-47f3-422c-a317-be72f08d6aef",
:page 349,
:position {:bounding {:x1 0,
:y1 173.14286613464355,
:x2 689.8495903015137,
:y2 474.5625305175781,
:width 864,
:height 1296},
:rects ({:x1 0,
:y1 173.14286613464355,
:x2 0,
:y2 194.28572463989258,
:width 864,
:height 1296}
{:x1 140.01786422729492,
:y1 436.919677734375,
:x2 689.8495903015137,
:y2 454.6339416503906,
:width 864,
:height 1296}
{:x1 116.09821891784668,
:y1 456.8482360839844,
:x2 576.551923751831,
:y2 474.5625305175781,
:width 864,
:height 1296}),
:page 349},
:content {:text "The load-linked operates much like a typical load instruction, and simply fetches a value from memory and places it in a register. "},
:properties {:color "yellow"}}
{:id #uuid "6434fe62-0e92-4414-86cc-b0c37fcf51ec",
:page 349,
:position {:bounding {:x1 0,
:y1 205.1428680419922,
:x2 691.6227188110352,
:y2 574.4018249511719,
:width 864,
:height 1296},
:rects ({:x1 0,
:y1 205.1428680419922,
:x2 0,
:y2 226.28572845458984,
:width 864,
:height 1296}
{:x1 0,
:y1 221.1428680419922,
:x2 0,
:y2 242.28572845458984,
:width 864,
:height 1296}
{:x1 0,
:y1 237.1428680419922,
:x2 0,
:y2 258.28572845458984,
:width 864,
:height 1296}
{:x1 0,
:y1 253.1428680419922,
:x2 0,
:y2 274.28572845458984,
:width 864,
:height 1296}
{:x1 277.6942825317383,
:y1 476.76788330078125,
:x2 689.7750625610352,
:y2 494.482177734375,
:width 864,
:height 1296}
{:x1 116.09821891784668,
:y1 496.6964416503906,
:x2 689.7808971405029,
:y2 514.6250305175781,
:width 864,
:height 1296}
{:x1 116.09821891784668,
:y1 516.6250305175781,
:x2 690.9502334594727,
:y2 534.5535888671875,
:width 864,
:height 1296}
{:x1 116.09821891784668,
:y1 536.5535888671875,
:x2 691.6227188110352,
:y2 554.482177734375,
:width 864,
:height 1296}
{:x1 116.09821891784668,
:y1 556.4732360839844,
:x2 505.1802444458008,
:y2 574.4018249511719,
:width 864,
:height 1296}),
:page 349},
:content {:text "store-conditional, which only succeeds (and updates the value stored at the address just load-linked from) if no intervening store to the address has taken place. In the case of success, the storeconditional returns 1 and updates the value at ptr to value; if it fails, the value at ptr is not updated and 0 is returned."},
:properties {:color "yellow"}}
{:id #uuid "64350170-c853-4080-9ed1-2777ea3a18c8",
:page 350,
:position {:bounding {:x1 171.88932037353516,
:y1 863.3928833007812,
:x2 325.20848846435547,
:y2 885.1071624755859,
:width 864,
:height 1296},
:rects ({:x1 171.88932037353516,
:y1 863.3928833007812,
:x2 325.20848846435547,
:y2 885.1071624755859,
:width 864,
:height 1296}),
:page 350},
:content {:text "Fetch-And-Add"},
:properties {:color "yellow"}}
{:id #uuid "643501c1-f11b-4e85-8125-d2a5a31f69b0",
:page 351,
:position {:bounding {:x1 287.3301315307617,
:y1 215.3393006324768,
:x2 330.14022064208984,
:y2 233.0535798072815,
:width 864,
:height 1296},
:rects ({:x1 287.3301315307617,
:y1 215.3393006324768,
:x2 330.14022064208984,
:y2 233.0535798072815,
:width 864,
:height 1296}),
:page 351},
:content {:text "brag "},
:properties {:color "green"}}
{:id #uuid "64350331-8fbb-4c41-9ac1-1a4ba852f772",
:page 351,
:position {:bounding {:x1 116.09821701049805,
:y1 483.9285888671875,
:x2 203.6010856628418,
:y2 507.3571472167969,
:width 864,
:height 1296},
:rects ({:x1 116.09821701049805,
:y1 483.9285888671875,
:x2 203.6010856628418,
:y2 507.3571472167969,
:width 864,
:height 1296}),
:page 351},
:content {:text "ticket lock"},
:properties {:color "yellow"}}
{:id #uuid "64350420-ca8a-4cac-af2f-f4e7deb5d1be",
:page 351,
:position {:bounding {:x1 0,
:y1 413.1428680419922,
:x2 738.2561340332031,
:y2 816.4464416503906,
:width 921.6,
:height 1382.4},
:rects ({:x1 0,
:y1 413.1428680419922,
:x2 0,
:y2 434.2857208251953,
:width 921.6,
:height 1382.4}
{:x1 204.68063354492188,
:y1 775.7679138183594,
:x2 738.2561340332031,
:y2 795.1964416503906,
:width 921.6,
:height 1382.4}
{:x1 123.83928871154785,
:y1 797.0179138183594,
:x2 618.5764713287354,
:y2 816.4464416503906,
:width 921.6,
:height 1382.4}),
:page 351},
:content {:text "it ensures progress for all threads. Once a thread is assigned its ticket value, it will be scheduled at some point in the future"},
:properties {:color "yellow"}}
{:id #uuid "64350781-6995-41db-8b8e-2de0eb84136a",
:page 353,
:position {:bounding {:x1 336.0178756713867,
:y1 439.3214416503906,
:x2 629.7097702026367,
:y2 464.46429443359375,
:width 921.6,
:height 1382.4},
:rects ({:x1 336.0178756713867,
:y1 439.3214416503906,
:x2 629.7097702026367,
:y2 464.46429443359375,
:width 921.6,
:height 1382.4}),
:page 353},
:content {:text "Lock With Test-and-set And Yield"},
:properties {:color "yellow"}}
{:id #uuid "643507af-1153-46c1-b232-31a9a203e5df",
:page 353,
:position {:bounding {:x1 0,
:y1 269.1428756713867,
:x2 738.272834777832,
:y2 606.2500381469727,
:width 921.6,
:height 1382.4},
:rects ({:x1 0,
:y1 269.1428756713867,
:x2 0,
:y2 290.28572845458984,
:width 921.6,
:height 1382.4}
{:x1 0,
:y1 285.1428756713867,
:x2 0,
:y2 306.28572845458984,
:width 921.6,
:height 1382.4}
{:x1 233.25476837158203,
:y1 544.3125381469727,
:x2 738.272834777832,
:y2 563.741096496582,
:width 921.6,
:height 1382.4}
{:x1 123.83929443359375,
:y1 563.9821853637695,
:x2 202.37335205078125,
:y2 589.1250381469727,
:width 921.6,
:height 1382.4}
{:x1 306.8750228881836,
:y1 563.9821853637695,
:x2 363.09754180908203,
:y2 589.1250381469727,
:width 921.6,
:height 1382.4}
{:x1 123.83929443359375,
:y1 567.4107437133789,
:x2 738.1959915161133,
:y2 586.8393020629883,
:width 921.6,
:height 1382.4}
{:x1 123.83929443359375,
:y1 586.8214492797852,
:x2 199.30642700195312,
:y2 606.2500381469727,
:width 921.6,
:height 1382.4}),
:page 353},
:content {:text "yield is simply a system call that moves the caller from the running state to the ready state, and thus promotes another thread to running. "},
:properties {:color "yellow"}}
{:id #uuid "6435099b-0834-483e-9ef2-98a0b795cf00",
:page 355,
:position {:bounding {:x1 381.2857208251953,
:y1 336.4643096923828,
:x2 535.9663848876953,
:y2 361.6071319580078,
:width 921.6,
:height 1382.4},
:rects ({:x1 381.2857208251953,
:y1 336.4643096923828,
:x2 535.9663848876953,
:y2 361.6071319580078,
:width 921.6,
:height 1382.4}),
:page 355},
:content {:text "priority inversion"},
:properties {:color "yellow"}}
{:id #uuid "643509b5-12a0-4ed9-8a96-f70b3fc0e373",
:page 355,
:position {:bounding {:x1 149.39746856689453,
:y1 359.30358123779297,
:x2 268.7185363769531,
:y2 378.73217010498047,
:width 921.6,
:height 1382.4},
:rects ({:x1 149.39746856689453,
:y1 359.30358123779297,
:x2 268.7185363769531,
:y2 378.73217010498047,
:width 921.6,
:height 1382.4}),
:page 355},
:content {:text "intergalactic "},
:properties {:color "green"}}
{:id #uuid "643509ba-662e-4d0a-906a-fd0987e24574",
:page 355,
:position {:bounding {:x1 268.71058654785156,
:y1 359.30358123779297,
:x2 328.3750915527344,
:y2 378.73217010498047,
:width 921.6,
:height 1382.4},
:rects ({:x1 268.71058654785156,
:y1 359.30358123779297,
:x2 328.3750915527344,
:y2 378.73217010498047,
:width 921.6,
:height 1382.4}),
:page 355},
:content {:text "scourge"},
:properties {:color "green"}}
{:id #uuid "64350b44-dfae-4544-93f9-ff2b343fefd4",
:page 354,
:position {:bounding {:x1 314.14287185668945,
:y1 927.5714721679688,
:x2 770.6213264465332,
:y2 952.7143249511719,
:width 921.6,
:height 1382.4},
:rects ({:x1 314.14287185668945,
:y1 927.5714721679688,
:x2 770.6213264465332,
:y2 952.7143249511719,
:width 921.6,
:height 1382.4}),
:page 354},
:content {:text "Lock With Queues, Test-and-set, Yield, And Wakeup"},
:properties {:color "yellow"}}
{:id #uuid "64350b4e-9559-49d9-aa37-eda9fe425b7f",
:page 353,
:position {:bounding {:x1 0,
:y1 621.1428756713867,
:x2 738.2636413574219,
:y2 1106.0625305175781,
:width 921.6,
:height 1382.4},
:rects ({:x1 0,
:y1 621.1428756713867,
:x2 0,
:y2 642.2857360839844,
:width 921.6,
:height 1382.4}
{:x1 149.35714721679688,
:y1 1065.3839721679688,
:x2 738.2636413574219,
:y2 1084.8125305175781,
:width 921.6,
:height 1382.4}
{:x1 123.83929443359375,
:y1 1086.6339721679688,
:x2 265.7547607421875,
:y2 1106.0625305175781,
:width 921.6,
:height 1382.4}),
:page 353},
:content {:text "The real problem with our previous approaches is that they leave too much to chance."},
:properties {:color "yellow"}}
{:id #uuid "64350bfb-64f7-4d41-8cc2-260dbec3372d",
:page 354,
:position {:bounding {:x1 267.0446472167969,
:y1 1086.6339721679688,
:x2 590.4763793945312,
:y2 1106.0625610351562,
:width 921.6,
:height 1382.4},
:rects ({:x1 267.0446472167969,
:y1 1086.6339721679688,
:x2 590.4763793945312,
:y2 1106.0625610351562,
:width 921.6,
:height 1382.4}),
:page 354},
:content {:text "park() to put a calling thread to sleep"},
:properties {:color "yellow"}}
{:id #uuid "64350c01-39bb-4d15-b554-0287b13806ee",
:page 354,
:position {:bounding {:x1 0,
:y1 669.1428909301758,
:x2 816.99169921875,
:y2 1127.3214721679688,
:width 921.6,
:height 1382.4},
:rects ({:x1 0,
:y1 669.1428909301758,
:x2 0,
:y2 690.2857475280762,
:width 921.6,
:height 1382.4}
{:x1 633.232177734375,
:y1 1086.6339721679688,
:x2 816.99169921875,
:y2 1106.0625610351562,
:width 921.6,
:height 1382.4}
{:x1 183.3571434020996,
:y1 1107.8929138183594,
:x2 415.88805770874023,
:y2 1127.3214721679688,
:width 921.6,
:height 1382.4}),
:page 354},
:content {:text "unpark(threadID) to wake a particular thread"},
:properties {:color "yellow"}}
{:id #uuid "64351ba3-d4b5-4999-bc61-7733d5e0a061",
:page 356,
:position {:bounding {:x1 569.2232360839844,
:y1 702.4732360839844,
:x2 751.833984375,
:y2 727.6161193847656,
:width 921.6,
:height 1382.4},
:rects ({:x1 569.2232360839844,
:y1 702.4732360839844,
:x2 751.833984375,
:y2 727.6161193847656,
:width 921.6,
:height 1382.4}),
:page 356},
:content {:text "wakeup/waiting race"},
:properties {:color "yellow"}}
{:id #uuid "64351e9a-6505-4176-a6fb-ddf63f3245a8",
:page 356,
:position {:bounding {:x1 471.6607360839844,
:y1 1127.5625610351562,
:x2 516.3173828125,
:y2 1152.7054138183594,
:width 921.6,
:height 1382.4},
:rects ({:x1 471.6607360839844,
:y1 1127.5625610351562,
:x2 516.3173828125,
:y2 1152.7054138183594,
:width 921.6,
:height 1382.4}),
:page 356},
:content {:text "futex"},
:properties {:color "yellow"}}
{:id #uuid "64352221-d590-4371-a5f0-29e9cfa75ccb",
:page 357,
:position {:bounding {:x1 265.9553680419922,
:y1 829.5625305175781,
:x2 596.0395202636719,
:y2 854.7054138183594,
:width 921.6,
:height 1382.4},
:rects ({:x1 379.21429443359375,
:y1 829.5625305175781,
:x2 596.0395202636719,
:y2 854.7054138183594,
:width 921.6,
:height 1382.4}
{:x1 265.9553680419922,
:y1 831.1429138183594,
:x2 379.2243347167969,
:y2 850.5714721679688,
:width 921.6,
:height 1382.4}),
:page 357},
:content {:text "Figure 28.10: Linux-based Futex Locks"},
:properties {:color "yellow"}}
{:id #uuid "643522a7-4b16-4998-9b2f-47a852681a16",
:page 358,
:position {:bounding {:x1 0,
:y1 157.14286422729492,
:x2 797.6362762451172,
:y2 485.67858505249023,
:width 921.6,
:height 1382.4},
:rects ({:x1 0,
:y1 157.14286422729492,
:x2 0,
:y2 178.28571701049805,
:width 921.6,
:height 1382.4}
{:x1 707.2857513427734,
:y1 439.2767906188965,
:x2 797.6362762451172,
:y2 464.41967391967773,
:width 921.6,
:height 1382.4}
{:x1 183.3571548461914,
:y1 460.5357322692871,
:x2 220.56002044677734,
:y2 485.67858505249023,
:width 921.6,
:height 1382.4}
{:x1 183.3571548461914,
:y1 463.9643211364746,
:x2 220.56002044677734,
:y2 483.0893211364746,
:width 921.6,
:height 1382.4}),
:page 358},
:content {:text "two-phase lock"},
:properties {:color "yellow"}}
{:id #uuid "6435230e-d84a-4c91-8329-b7608b0d543a",
:page 358,
:position {:bounding {:x1 0,
:y1 189.14286422729492,
:x2 797.7836151123047,
:y2 524.0535850524902,
:width 921.6,
:height 1382.4},
:rects ({:x1 0,
:y1 189.14286422729492,
:x2 0,
:y2 210.28571701049805,
:width 921.6,
:height 1382.4}
{:x1 498.4398956298828,
:y1 483.37502670288086,
:x2 797.7836151123047,
:y2 502.80358505249023,
:width 921.6,
:height 1382.4}
{:x1 183.3571548461914,
:y1 504.62502670288086,
:x2 546.6940078735352,
:y2 524.0535850524902,
:width 921.6,
:height 1382.4}),
:page 358},
:content {:text "in the first phase, the lock spins for a while, hoping that it can acquire the lock."},
:properties {:color "yellow"}}
{:id #uuid "64352344-d140-468c-987c-e8afa05c2171",
:page 358,
:position {:bounding {:x1 0,
:y1 221.14286422729492,
:x2 797.7610244750977,
:y2 587.8214378356934,
:width 921.6,
:height 1382.4},
:rects ({:x1 0,
:y1 221.14286422729492,
:x2 0,
:y2 242.2857322692871,
:width 921.6,
:height 1382.4}
{:x1 0,
:y1 237.14286422729492,
:x2 0,
:y2 258.2857322692871,
:width 921.6,
:height 1382.4}
{:x1 298.8221740722656,
:y1 525.8750267028809,
:x2 797.7419738769531,
:y2 545.3036155700684,
:width 921.6,
:height 1382.4}
{:x1 183.3571548461914,
:y1 547.1339378356934,
:x2 797.7610244750977,
:y2 566.5625267028809,
:width 921.6,
:height 1382.4}
{:x1 183.3571548461914,
:y1 568.3929100036621,
:x2 464.9660415649414,
:y2 587.8214378356934,
:width 921.6,
:height 1382.4}),
:page 358},
:content {:text " the lock is not acquired during the first spin phase, a second phase is entered, where the caller is put to sleep, and only woken up when the lock becomes free later."},
:properties {:color "yellow"}}],
:extra {:page 345}}
:extra {:page 361}}

View File

@ -7,6 +7,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
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
@ -32,6 +33,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
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
@ -68,6 +70,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
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
@ -79,6 +82,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
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**:
@ -94,6 +98,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
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.
@ -105,6 +110,7 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
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
@ -115,19 +121,282 @@ file-path:: ../assets/ostep_1681115599584_0.pdf
- Problem
- When interrupted between load and test, *mutual exclusion* is broken.
- Low efficiency because of spin-waiting.
- Spin Locks with Test-And-Set
ls-type:: annotation
hl-page:: 344
hl-color:: yellow
id:: 64340154-807c-4a7a-b783-045d5d6d3927
- **test-and-set (or atomic exchange) instruction**
hl-page:: 344
- **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:: 643401e0-fcec-41d3-9898-d5c4175ac464
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
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
- intergalactic
ls-type:: annotation
hl-page:: 355
hl-color:: green
id:: 643509b5-12a0-4ed9-8a96-f70b3fc0e373
- scourge
ls-type:: annotation
hl-page:: 355
hl-color:: green
id:: 643509ba-662e-4d0a-906a-fd0987e24574