рдлреНрдпреВрдЯреЗрдХреНрд╕ рдореВрд▓ рдмрд╛рддреЗрдВ

Futex (futex - "рдлрд╛рд╕реНрдЯ рдпреВрдЬрд╝рд░реНрд╕рд╕реНрдкреЗрд╕ рдореНрдпреВрдЯреЗрдХреНрд╕" рдХреЗ рд▓рд┐рдП) 2002 рдореЗрдВ IBM рдХреЗ рд▓рд┐рдирдХреНрд╕ рдбреЗрд╡рд▓рдкрд░реНрд╕ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рдПрдХ рддрдВрддреНрд░ рд╣реИ рдФрд░ 2003 рдХреЗ рдЕрдВрдд рдореЗрдВ рдХрд░реНрдиреЗрд▓ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд┐рдпрд╛ред рдореБрдЦреНрдп рд╡рд┐рдЪрд╛рд░ рдУрдПрд╕ рдХрд░реНрдиреЗрд▓ рдХреЗ рд▓рд┐рдП рдиреНрдпреВрдирддрдо рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдереНрд░реЗрдб рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рдХреБрд╢рд▓ рддрд░реАрдХрд╛ рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдерд╛ред

рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рдлреНрдпреВрдЯреЗрдХреНрд╕ рдХреА рд╕рдореАрдХреНрд╖рд╛ рдХрд░реЗрдВрдЧреЗ, рдЙрдирдХреЗ рдХрд╛рдо рдХреЗ рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдХреЛ рд╕рдордЭрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВрдЧреЗ, рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЙрдЪреНрдЪ-рд╕реНрддрд░реАрдп (рдФрд░ рд╣рдорд╕реЗ рдкрд░рд┐рдЪрд┐рдд) рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдИрдВрдЯреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рднреА рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред

рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд┐рдВрджреБ: рдлреНрдпреВрдЯреЗрдХреНрд╕ рдПрдХ рдмрд▓реНрдХрд┐ рдирд┐рдореНрди-рд╕реНрддрд░реАрдп рдЙрдкрдХрд░рдг рд╣реИ, рдпрд╣ рдХреЗрд╡рд▓ рдореМрд▓рд┐рдХ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдХреЗ рджреМрд░рд╛рди рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд╛рдпрдХ рд╣реИ, рдЬреИрд╕реЗ рдХрд┐ рдорд╛рдирдХ рд╕реА / рд╕реА ++ рдкреБрд╕реНрддрдХрд╛рд▓рдпред рдпрд╣ рдмрд╣реБрдд рд╕рдВрднрд╛рд╡рдирд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдПрдХ рдирд┐рдпрдорд┐рдд рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдВ рдлрд╝реНрдпреВрдЯреЗрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред

рдкреНрд░реЗрд░рдгрд╛


рдлрд╝реБрдЯреЗрдХреНрд╕ рдХреЗ рдЖрдЧрдорди рд╕реЗ рдкрд╣рд▓реЗ, рдХрдИ рдереНрд░реЗрдбреНрд╕ рд╕реЗ рд╕рд╛рдЭрд╛ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рддрдХ рдкрд╣реБрдВрдЪ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рд░ рдмрд╛рд░ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╕реЗрдореНрдк ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдерд╛, рдЬреЛ рдХрд┐ рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ, рд╕рдВрд╕рд╛рдзрди-рдЧрд╣рди рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдХреЙрд▓ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдореЛрдб рд╕реЗ рдХрд░реНрдиреЗрд▓ рдореЛрдб рдореЗрдВ рд╕рдВрджрд░реНрдн рдХреЛ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдЖрдзреБрдирд┐рдХ рдкреНрд░реЛрд╕реЗрд╕рд░ рдореЗрдВ рдХреЛрд░ рдХреА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд╡реГрджреНрдзрд┐ рдФрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕реЙрдлрд╝реНрдЯрд╡реЗрдпрд░ рдореЗрдВ рдереНрд░реЗрдб рдХреА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд╡реГрджреНрдзрд┐ рдХреЗ рд╕рд╛рде, рдпрд╣ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╕рдорд╕реНрдпрд╛ рдмрди рдЧрдИ рд╣реИред рдпрд╣ рдФрд░ рднреА рдЕрдзрд┐рдХ "рдЕрдкрдорд╛рдирдЬрдирдХ" рд╣реИ, рдпрд╣ рджреЗрдЦрддреЗ рд╣реБрдП рдХрд┐ рдпреЗ рд╕рднреА рдХреЙрд▓ рдХрд┐рд╕реА рднреА рд▓рд╛рдЧреВ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рдХрд┐рд╕реА рднреА рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рдХреЛ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рдмрд╛рдХреА рдХреЛрдб рдХреЗ рд╕рд╣реА рд╕рдВрдЪрд╛рд▓рди рдХреА рдЧрд╛рд░рдВрдЯреА рджреЗрддреЗ рд╣реИрдВред

OS рдореЗрдВ "futex" рдХреА рдПрдХ рдирдИ рдЕрд╡рдзрд╛рд░рдгрд╛ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЕрд╡рд▓реЛрдХрди рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдерд╛: рдЬреНрдпрд╛рджрд╛рддрд░ рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдкрд╣рд▓реА рдмрд╛рд░ рд╕рдлрд▓ рд╣реЛрддрд╛ рд╣реИред рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рд▓рд┐рдЦрддреЗ рд╣реИрдВ рдХрд┐ рд▓реЙрдХ рдХреЛ рд▓реЙрдХ рдХрд░рдиреЗ рд╕реЗ рд▓реЗрдХрд░ рдЙрд╕реЗ рдЕрдирд▓реЙрдХ рдХрд░рдиреЗ рдореЗрдВ рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рдЙрддрдирд╛ рдХрдо рд╕рдордп рдмреАрддрддрд╛ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛рдПрдВ рд╣реИрдВ рдХрд┐ рджреВрд╕рд░реЗ рдзрд╛рдЧреЗ рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдмрд╛рдзрд╛рдУрдВ рдХрд╛ рд╕рд╛рдордирд╛ рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рдЬрдм рдХреЛрдИ рдзрд╛рд░рд╛ рдРрд╕реЗ "рдореБрдХреНрдд" рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдСрдмреНрдЬреЗрдХреНрдЯ рддрдХ рдкрд╣реБрдВрдЪрддреА рд╣реИ, рддреЛ рд╣рдо рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рд╕рд╕реНрддреЗ рдкрд░рдорд╛рдгреБ рд╕рдВрдЪрд╛рд▓рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХрд┐рдП рдмрд┐рдирд╛ рдЗрд╕реЗ рдХреИрдкреНрдЪрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдФрд░ рдПрдХ рдмрд╣реБрдд рдмрдбрд╝реА рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рдкрд░рдорд╛рдгреБ рдСрдкрд░реЗрд╢рди рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдХрд╛рдо рдХрд░реЗрдЧрд╛ред

рдЙрд╕ рджреБрд░реНрд▓рдн рдорд╛рдорд▓реЗ рдореЗрдВ, рдЬрдм рд╣рдо рдЕрднреА рднреА рдХрд┐рд╕реА рдЕрдиреНрдп рдереНрд░реЗрдб рджреНрд╡рд╛рд░рд╛ рдЕрд╡рд░реБрджреНрдз рд╕рдВрд╕рд╛рдзрди рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдПрдХ рдкрд░рдорд╛рдгреБ рдСрдкрд░реЗрд╢рди рдПрдХ рддреНрд░реБрдЯрд┐ рд▓реМрдЯрд╛рдПрдЧрд╛ред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рджреЛ рд╡рд┐рдХрд▓реНрдк рд╣реИрдВред рд╣рдо рдпрд╛ рддреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдореЛрдб рдХреЗ рдХреБрдЫ рд╕реНрдкрд┐рди-рд▓реЙрдХ рдореЗрдВ рд╕реНрдкрд┐рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд╕рдВрд╕рд╛рдзрди рдХреА рд░рд┐рд╣рд╛рдИ (рдЬреЛ рд╕реАрдкреАрдпреВ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рдЦрд╛рдПрдВрдЧреЗ) рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдпрд╛ рдХрд░реНрдиреЗрд▓ рд╕реЗ рд╣рдореЗрдВ рдиреАрдВрдж рдореЛрдб рдореЗрдВ рдбрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣ рд╕рдХрддреЗ рд╣реИрдВ, рд╕рдВрд╕рд╛рдзрди рдХреА рд░рд┐рд╣рд╛рдИ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдБ futexes рджреГрд╢реНрдп рдкрд░ рдЖрддреЗ рд╣реИрдВред

рдлреНрдпреВрдЯреЗрдХреНрд╕ рдХрд╛ рд╕рд░рд▓ рдЙрдкрдпреЛрдЧ - рдЙрдореНрдореАрдж рдФрд░ рдЬрд╛рдЧреГрддрд┐


рдлреНрдпреВрдЯреЗрдХреНрд╕ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХрд╛рдлреА рдкреНрд░рдХрд╛рд░ рдХреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рдЬреЛрдбрд╝рддреА рд╣реИред рд╣рдо рдпрд╣рд╛рдВ рдЬрдЯрд┐рд▓ рд╡рд┐рдХрд▓реНрдкреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ (рдЙрдирдореЗрдВ рд╕реЗ рдХреБрдЫ рдЗрддрдиреЗ рд╡рд┐рд╕реНрддреГрдд рд╣реИрдВ рдХрд┐ рдЙрдиреНрд╣реЗрдВ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рджрд╕реНрддрд╛рд╡реЗрдЬ рдореЗрдВ рднреА рд╡рд░реНрдгрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ), рд▓реЗрдХрд┐рди рд╣рдо FUTEX_WAIT рдФрд░ FUTEX_WAKE рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдХрд░реЗрдВрдЧреЗред рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рджрд╕реНрддрд╛рд╡реЗрдЬ рдореЗрдВ рд╡рд┐рд╡рд░рдг рдПрдХ рдЕрдЪреНрдЫреЗ рдЖрдзрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░реЗрдЧрд╛:
рдлрд╝реБрдЯреЗрдХреНрд╕ () рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреА рд╡рд┐рдзрд┐ рдХреЗ рд╕рд╛рде рдкреНрд░реЛрдЧреНрд░рд╛рдо рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рддрд╛рдХрд┐ рд╡рд╣ рд╕рдЪ рд╣реЛ рд╕рдХреЗред рдЖрдорддреМрд░ рдкрд░, рдпрд╣ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рд╕рд╛рдЭрд╛ рдореЗрдореЛрд░реА рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдПрдХ рдЕрд╡рд░реБрджреНрдз рдирд┐рд░реНрдорд╛рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рдлрд╝реБрдЯреЗрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕реНрдерд╛рди рдореЗрдВ рдореБрдЦреНрдп рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдСрдкрд░реЗрд╢рди рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдВрддрд░рд┐рдХреНрд╖ рдХрд╛рд░реНрдпрдХреНрд░рдо рдлреНрдпреВрдЯреЗрдХреНрд╕ () рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХреЛ рддрднреА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдЬрдм рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЛ рд▓рдВрдмреЗ рд╕рдордп рддрдХ рд╕реНрдЯреИрдВрдбрдмрд╛рдп рдореЛрдб рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реЛрддрд╛ рд╣реИ рдЬрдм рддрдХ рдХрд┐ рд╕реНрдерд┐рддрд┐ рд╕рд╣реА рдирд╣реАрдВ рд╣реЛ рдЬрд╛рддреАред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, futex () рдХрд╛ рдЙрдкрдпреЛрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдпрд╛ рдзрд╛рдЧреЛрдВ рдХреЛ рдЬрдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЬреЛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕реНрдерд┐рддрд┐ рдХреА рдЙрдореНрдореАрдж рдХрд░рддреЗ рд╣реИрдВред
рд╕реАрдзреЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ рдХрд╣реЗрдВ, рдПрдХ рдлреВрдЯреЗрдХреНрд╕ рдПрдХ рдХрд░реНрдиреЗрд▓ рдирд┐рд░реНрдорд╛рдг рд╣реИ рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛрдб рдХреЛ рдХреБрдЫ рд╣реЛрдиреЗ рдкрд░ рдереНрд░реЗрдб рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред рдХреБрдЫ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдПрдБ (рдпрд╛ рдереНрд░реЗрдбреНрд╕) FUTEX_WAIT рдХреЙрд▓ рдореЗрдВ рдШрдЯрдирд╛рдУрдВ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд╕рдХрддреА рд╣реИрдВ, рдЬрдмрдХрд┐ рдЕрдиреНрдп рдЗрди рдШрдЯрдирд╛рдУрдВ рдХреЛ FUTEX_WAKE рдХреЗ рд╕рд╛рде рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдкреНрд░рддреАрдХреНрд╖рд╛рд░рдд рдХреБрд╢рд▓рддрд╛ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ - рдкреНрд░рддреАрдХреНрд╖рд╛ рд╕реВрддреНрд░ рдХрд░реНрдиреЗрд▓ рджреНрд╡рд╛рд░рд╛ рдирд┐рд▓рдВрдмрд┐рдд рдХрд░ рджрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ рдФрд░ рдкреНрд░реЛрд╕реЗрд╕рд░ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ рдЬрдм рддрдХ рдХрд┐ рд╡реЗ рдПрдХ рдЕрдкреЗрдХреНрд╖рд┐рдд рдШрдЯрдирд╛ рд╣реЛрдиреЗ рдкрд░ рдЬрд╛рдЧреГрдд рди рд╣реЛрдВред

рдкреНрд░рд▓реЗрдЦрди рдХреЛ рд╕рдВрдкреВрд░реНрдгрддрд╛ рдореЗрдВ рдкрдврд╝рдиреЗ рдХрд╛ рд╕рдордп рдирд┐рдХрд╛рд▓реЗрдВред рдЦреИрд░, рдпрд╛ рдХрдо рд╕реЗ рдХрдо FUTEX_WAIT рдФрд░ FUTEX_WAKE рдкрд░ рдЕрдиреБрднрд╛рдЧ рдкрдврд╝реЗрдВред

рдЖрдЗрдП рдПрдХ рд╕рд░рд▓ рдЙрджрд╛рд╣рд░рдг рджреЗрдЦреЗрдВ рдЬреЛ рджреЛ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рдХрд╛рдо рдХреЛ рд╕рдордиреНрд╡рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлреНрдпреВрдЯреЗрдХреНрд╕ рдХреЗ рдореВрд▓ рдЙрдкрдпреЛрдЧ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред

рдмрд╛рд▓ рдкреНрд░рдХреНрд░рд┐рдпрд╛:

  1. рд╕рд╛рдорд╛рдиреНрдп рдореЗрдореЛрд░реА рд╕реНрд▓реЙрдЯ рдореЗрдВ 0xA рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИ
  2. рдЗрд╕ рд╕реНрд▓реЙрдЯ рдореЗрдВ рдорд╛рди 0xB рд▓рд┐рдЦрддрд╛ рд╣реИ

рдЗрд╕ рд╕рдордп рдХреА рдореВрд▓ рдкреНрд░рдХреНрд░рд┐рдпрд╛:

  1. рд╕рд╛рдЭрд╛ рдореЗрдореЛрд░реА рд╕реНрд▓реЙрдЯ рдореЗрдВ 0xA рдорд╛рди рд▓рд┐рдЦрддрд╛ рд╣реИ
  2. рдЗрд╕рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП 0xB рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рддрд╛ рд╣реИ

рджреЛ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рдмреАрдЪ рдРрд╕рд╛ "рд╣реИрдВрдбрд╢реЗрдХ"ред рдпрд╣рд╛рдБ рдХреЛрдб рд╣реИ:

int main(int argc, char** argv) { int shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666); if (shm_id < 0) { perror("shmget"); exit(1); } int* shared_data = shmat(shm_id, NULL, 0); *shared_data = 0; int forkstatus = fork(); if (forkstatus < 0) { perror("fork"); exit(1); } if (forkstatus == 0) { //   printf("child waiting for A\n"); wait_on_futex_value(shared_data, 0xA); printf("child writing B\n"); //  0xB         *shared_data = 0xB; wake_futex_blocking(shared_data); } else { //   printf("parent writing A\n"); //  0xA         *shared_data = 0xA; wake_futex_blocking(shared_data); printf("parent waiting for B\n"); wait_on_futex_value(shared_data, 0xB); // Wait for the child to terminate. wait(NULL); shmdt(shared_data); } return 0; } 

рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЗ рдмреАрдЪ рд╕рд╛рдЭрд╛ рдореЗрдореЛрд░реА рдХреЛ рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП POSIX рдХреЙрд▓ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВред рд╣рдо рдпрд╣рд╛рдВ рд╕рд╛рдорд╛рдиреНрдп рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рдореЗрдВ рд╕рдВрдХреЗрдд рдХрд╛ рдПрдХ рд╣реА рдкрддрд╛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдореЗрдореЛрд░реА рдмреНрд▓реЙрдХ (рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдЕрджреНрд╡рд┐рддреАрдп) рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░реЗрдЧрд╛ред

рдпрд╣ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдпрд╣ рдЙрджрд╛рд╣рд░рдг рддреЛрдкреЛрдВ рд╕реЗ рдХреБрдЫ рд╣рдж рддрдХ рд╡рд┐рдЪрд▓рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдлрд╝реБрдЯреЗрдХреНрд╕ рдореВрд▓ рд░реВрдк рд╕реЗ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдЕрд░реНрде "рдХреБрдЫ рд╡рд┐рд╢реЗрд╖ рд╕реЗ рдХреБрдЫ" рдореЗрдВ рдмрджрд▓рд╛рд╡ рдХреЗ рд▓рд┐рдП рдЗрдВрддрдЬрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛, рди рдХрд┐ "рдХреБрдЫ рд╕реЗ рдХреБрдЫ рд╡рд┐рд╢рд┐рд╖реНрдЯ" рдХреЗ рд▓рд┐рдПред рдЗрд╕ рддрд░рд╣ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореИрдВрдиреЗ рдпрд╣ рдЙрджрд╛рд╣рд░рдг рджрд┐рдпрд╛, рдФрд░ рдиреАрдЪреЗ рд╣рдо рдореВрд▓ рд╕рдВрд╕реНрдХрд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗ (рдЗрд╕ рдкрд░ рд╣рдо рдореНрдпреВрдЯреЗрдХреНрд╕ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ)ред

рдФрд░ рдпрд╣рд╛рдБ Wait_on_futex_value рдлрд╝рдВрдХреНрд╢рди рдХреЛрдб рд╣реИ:

 void wait_on_futex_value(int* futex_addr, int val) { while (1) { int futex_rc = futex(futex_addr, FUTEX_WAIT, val, NULL, NULL, 0); if (futex_rc == -1) { if (errno != EAGAIN) { perror("futex"); exit(1); } } else if (futex_rc == 0) { if (*futex_addr == val) { //    return; } } else { abort(); } } } 

рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдореБрдЦреНрдп рдХрд╛рд░реНрдп (рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдлрд╝реБрдЯреЗрдХреНрд╕ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓) рдПрдХ рдЪрдХреНрд░ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдЪрд▓рд╛рддреЗ рд╣реИрдВ рдЬрдм рд╣рдо рдЭреВрдареЗ рдЬрд╛рдЧрддреЗ рд╣реИрдВ (рд╣рдо рдореЗрдВ рд░реБрдЪрд┐ рдирд╣реАрдВ)ред рдпрд╣ рддрдм рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдЬрдм рдПрдХ рдирдпрд╛ рдореВрд▓реНрдп, рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реЗ рджреНрд╡рд╛рд░рд╛ рдЕрдкреЗрдХреНрд╖рд┐рдд рдирд╣реАрдВ рд╣реИ, рд╕рд╛рдЭрд╛ рдореЗрдореЛрд░реА рд╕реНрд▓реЙрдЯ рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рд╣реИред рдареАрдХ рд╣реИ, рдпрд╛ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдЬрдм рд╣рдорд╛рд░реА рддреБрд▓рдирд╛ рдореЗрдВ рдПрдХ рдФрд░ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкрд╣рд▓реЗ рдЬрд╛рдЧреГрдд рд╣реБрдИ рдереА (рдпрд╣ рд╣рдорд╛рд░реЗ рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЗ рдореЗрдВ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдзрд┐рдХ рд╕рд╛рдорд╛рдиреНрдп рддрд░реАрдХреЗ рд╕реЗ рдпрд╣ рд╕рдВрднрд╡ рд╣реИ)ред

Futex рд╢рдмреНрджрд╛рд░реНрде рдмрд╣реБрдд рдореБрд╢реНрдХрд┐рд▓ рд╕рд╛рдорд╛рди рд╣реИрдВ! FUTEX_WAIT рдХреЙрд▓ рддреБрд░рдВрдд рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧреА рдЕрдЧрд░ futex рдкрддреЗ рдкрд░ рдорд╛рди рдкрд╛рд░рд┐рдд рддрд░реНрдХ рдШрд╛рдЯреА рдХреЗ рдмрд░рд╛рдмрд░ рдирд╣реАрдВ рд╣реИред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рддрдм рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдЬрдм рдмрдЪреНрдЪреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдорд╛рддрд╛-рдкрд┐рддрд╛ рдиреЗ рд╕реНрд▓реЙрдЯ рдореЗрдВ рдореВрд▓реНрдп 0xA рд▓рд┐рдЦрд╛ рд╣реЛред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ futex EAGAIN рдорд╛рди рд▓реМрдЯрд╛рддрд╛ рд╣реИред

рдФрд░ рдпрд╣рд╛рдБ 'aw_futex_blocking' рдлрд╝рдВрдХреНрд╢рди рдХреЛрдб рд╣реИ:

 void wake_futex_blocking(int* futex_addr) { while (1) { int futex_rc = futex(futex_addr, FUTEX_WAKE, 1, NULL, NULL, 0); if (futex_rc == -1) { perror("futex wake"); exit(1); } else if (futex_rc > 0) { return; } } } 

рдпрд╣ FUTEX_WAKE рдкрд░ рдПрдХ рдЕрд╡рд░реЛрдзрдХ рдЖрд╡рд░рдг рд╣реИ рдЬреЛ рдЬрд▓реНрджреА рд╕реЗ рдХрд╛рдо рдХрд░реЗрдЧрд╛ рдФрд░ рдПрдХ рдореВрд▓реНрдп рд▓реМрдЯрд╛рдПрдЧрд╛, рдЪрд╛рд╣реЗ рдХрд┐рддрдиреЗ рднреА рд╢реНрд░реЛрддрд╛ рдЗрд╕рдХреА рдЙрдореНрдореАрдж рдХрд░реЗрдВред рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ "рд╣реИрдВрдбрд╢реЗрдХ" рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдиреНрдп рдЙрдкрдпреЛрдЧ рд╕рдВрднрд╡ рд╣реИрдВред

Futexes рдХрд╕реНрдЯрдо рдХреЛрдб рдХреЗ рд▓рд┐рдП рдХрд░реНрдиреЗрд▓ рдХрддрд╛рд░ рд╣реИрдВред


рд╕реАрдзреЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ рдХрд╣реЗрдВ, рдПрдХ рдлреВрдЯреЗрдХреНрд╕ рдХрд╕реНрдЯрдо рдХреЛрдб рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЧрд┐рд░реА рдЪрд╛рд▓рд┐рдд рдХрддрд╛рд░ рд╣реИред рдпрд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛрдб рдХреЛ рдХрд░реНрдиреЗрд▓ рд╕реЗ рдЕрдкрдиреЗ рдзрд╛рдЧреЗ рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЛ рдирд┐рд▓рдВрдмрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рддрд╛ рд╣реИ рдЬрдм рддрдХ рдХрд┐ рдХреЛрдИ рдШрдЯрдирд╛ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ, рдФрд░ рдЗрд╕ рдШрдЯрдирд╛ рдХреЛ рд╕рдВрдХреЗрдд рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдФрд░ рджреВрд╕рд░реЗ рдзрд╛рдЧреЗ рдХреЛ рдЗрд╕рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣реЗ рд╕рднреА рдереНрд░реЗрдбреНрд╕ рдХреЛ рдЬрдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдПред рдкрд╣рд▓реЗ рд╣рдордиреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдореЛрдб рдореЗрдВ рд╕реНрдкрд┐рди-рд▓реЙрдХ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдерд╛, рдХреБрдЫ рд╢рд░реНрдд рдкреВрд░реА рд╣реЛрдиреЗ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣рд╛ рдерд╛ред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдХрд░реНрдиреЗрд▓ рдореЗрдВ рдХрддрд╛рд░ рдПрдХ рдмреЗрд╣рддрд░ рд╡рд┐рдХрд▓реНрдк рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╣рдореЗрдВ рдПрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рд▓реВрдк рдореЗрдВ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдЕрд░рдмреЛрдВ рд╡реНрдпрд░реНрде рдкреНрд░реЛрд╕реЗрд╕рд░ рдирд┐рд░реНрджреЗрд╢реЛрдВ рд╕реЗ рдмрдЪрд╛рддрд╛ рд╣реИред

рдпрд╣рд╛рдБ рд▓реЗрдЦ "рдПрдХ futex рдЕрд╡рд▓реЛрдХрди рдФрд░ рдЕрджреНрдпрддрди" рд╕реЗ рдЪрд┐рддреНрд░ рдкрд░ рд╣реИ:

рдЫрд╡рд┐

рд▓рд┐рдирдХреНрд╕ рдХрд░реНрдиреЗрд▓ рдХреЛрдб рдореЗрдВ, futexes рдХреЛ рдХрд░реНрдиреЗрд▓ / futex.c рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдХрд░реНрдиреЗрд▓ рдПрдХ рд╣реИрд╢ рддрд╛рд▓рд┐рдХрд╛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рдХреБрдВрдЬреА рдкрддреЗ рд╣реИрдВ - рдЬрд▓реНрджреА рд╕реЗ рд╡рд╛рдВрдЫрд┐рдд рдХрддрд╛рд░ рдХреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдФрд░ рдЗрд╕рдореЗрдВ рдХреЙрд▓рд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдЬреЛрдбрд╝реЗрдВред рд╕рдм рдХреБрдЫ, рдЬрд╝рд╛рд╣рд┐рд░ рд╣реИ, рдЗрддрдирд╛ рд╕рд░рд▓ рдирд╣реАрдВ рд╣реИ - рдЖрдЦрд┐рд░рдХрд╛рд░, рдХрд░реНрдиреЗрд▓ рдХреЛ рдЦреБрдж рдХреЛ рдЕрдВрджрд░ рдбреЗрдЯрд╛ рддрдХ рдкрд╣реБрдВрдЪ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рд╕рд╛рде рд╣реА рдлрд╝реНрдпреВрдЪреНрдпреВрдЬрд╝реЛрд╡ рдХреЗ рд▓рд┐рдП рд╕рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред

FUTEX_WAIT рдХреЗ рд╕рд╛рде рд╕рдордп-рд╕реАрдорд┐рдд рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдВ


рдлрд╝реБрдЯреЗрдХреНрд╕ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдореЗрдВ рдПрдХ рдЯрд╛рдЗрдордЖрдЙрдЯ рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИ рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдпрд╣ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдХрд┐ рд╡реЗ рдХрд┐рддрдиреА рджреЗрд░ рддрдХ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВред рдпрд╣рд╛рдВ рдПрдХ рдкреВрд░реНрдг рдЙрджрд╛рд╣рд░рдг рд╣реИ рдЬрд╣рд╛рдВ рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ рдкреНрд░рдореБрдЦ рднрд╛рдЧ рд╣реИ:

 printf("child waiting for A\n"); struct timespec timeout = {.tv_sec = 0, .tv_nsec = 500000000}; while (1) { unsigned long long t1 = time_ns(); int futex_rc = futex(shared_data, FUTEX_WAIT, 0xA, &timeout, NULL, 0); printf("child woken up rc=%d errno=%s, elapsed=%llu\n", futex_rc, futex_rc ? strerror(errno) : "", time_ns() - t1); if (futex_rc == 0 && *shared_data == 0xA) { break; } } 

рдпрджрд┐ рдкреНрд░рддреАрдХреНрд╖рд╛ 500 рдПрдордПрд╕ рдХреЗ рд▓рд┐рдП рджреЗрд░реА рд╣реЛ рд░рд╣реА рд╣реИ, рддреЛ рдлрд╝реБрдЯреЗрдХреНрд╕ рдлрд╝рдВрдХреНрд╢рди рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рд▓реВрдк рдХреЗ рдЕрдЧрд▓реЗ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдореЗрдВ рд╣рдо рдХрд┐рд╕реА рддрд░рд╣ рдЗрд╕ рдкрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рд╕реНрдХреНрд░реАрди рдкрд░ рдХреБрдЫ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВ, рд▓реЙрдЧ рдкрд░ рд▓рд┐рдЦреЗрдВ, рдкреНрд░рддреАрдХреНрд╖рд╛ рдЬрд╛рд░реА рд░рдЦреЗрдВ рдпрд╛ рд░реЛрдХреЗрдВ)ред

рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлреНрдпреВрдЯреЗрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛


рд╣рдордиреЗ рдЗрд╕ рд▓реЗрдЦ рдХреЛ рдЗрд╕ рддрдереНрдп рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд┐рдпрд╛ рдХрд┐ рдлрд╝реБрдЯреЗрдХреНрд╕ рдЙрдЪреНрдЪ-рд╕реНрддрд░реАрдп рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рдЙрдкрдпреЛрдЧ рдХреЗ рд╣реИрдВред рдЖрдЗрдП рдХреНрд▓рд╛рд╕рд┐рдХ рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдиреНрд╣реЗрдВ (рд╕рд╛рде рд╣реА рдПрдЯрдорд┐рдХреНрд╕) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВред рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЙрд▓рд░рд┐рдЪ рдбреНрд░реЗрдкрд░ рджреНрд╡рд╛рд░рд╛ рд▓рд┐рдЦрд┐рдд рд▓реЗрдЦ "рдлреНрдпреВрдЯреЗрдХреНрд╕ рдЯреНрд░рд┐рдХреА" рд╕реЗ рдХреЛрдб рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИред

рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореИрдВ C ++ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ, рдореБрдЦреНрдп рд░реВрдк рд╕реЗ C ++ 11 рдорд╛рдирдХ рд╕реЗ рдПрдЯрдорд┐рдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдХреЗ рд▓рд┐рдПред рдЖрдк рдкреВрд░реНрдг рдХреЛрдб рдпрд╣рд╛рдВ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣рд┐рд╕реНрд╕рд╛ рд╣реИ:

 class Mutex { public: Mutex() : atom_(0) {} void lock() { int c = cmpxchg(&atom_, 0, 1); // If the lock was previously unlocked, there's nothing else for us to do. // Otherwise, we'll probably have to wait. if (c != 0) { do { // If the mutex is locked, we signal that we're waiting by setting the // atom to 2. A shortcut checks is it's 2 already and avoids the atomic // operation in this case. if (c == 2 || cmpxchg(&atom_, 1, 2) != 0) { // Here we have to actually sleep, because the mutex is actually // locked. Note that it's not necessary to loop around this syscall; // a spurious wakeup will do no harm since we only exit the do...while // loop when atom_ is indeed 0. syscall(SYS_futex, (int*)&atom_, FUTEX_WAIT, 2, 0, 0, 0); } // We're here when either: // (a) the mutex was in fact unlocked (by an intervening thread). // (b) we slept waiting for the atom and were awoken. // // So we try to lock the atom again. We set teh state to 2 because we // can't be certain there's no other thread at this exact point. So we // prefer to err on the safe side. } while ((c = cmpxchg(&atom_, 0, 2)) != 0); } } void unlock() { if (atom_.fetch_sub(1) != 1) { atom_.store(0); syscall(SYS_futex, (int*)&atom_, FUTEX_WAKE, 1, 0, 0, 0); } } private: // 0 means unlocked // 1 means locked, no waiters // 2 means locked, there are waiters in lock() std::atomic<int> atom_; }; 

рдЗрд╕ рдХреЛрдб рдореЗрдВ, cmpxhg рдлрд╝рдВрдХреНрд╢рди рдкрд░рдорд╛рдгреБрдУрдВ рдХреЗ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд░рд▓ рдЖрд╡рд░рдг рд╣реИ:

 // An atomic_compare_exchange wrapper with semantics expected by the paper's // mutex - return the old value stored in the atom. int cmpxchg(std::atomic<int>* atom, int expected, int desired) { int* ep = &expected; std::atomic_compare_exchange_strong(atom, ep, desired); return *ep; } 

рдЗрд╕ рдХреЛрдб рдХреЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдХрдИ рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ рд╣реИрдВ рдЬреЛ рдЗрд╕рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЗ рддрд░реНрдХ рдХреА рд╡реНрдпрд╛рдЦреНрдпрд╛ рдХрд░рддреА рд╣реИрдВред рдпрд╣ рдЪреЛрдЯ рдирд╣реАрдВ рдкрд╣реБрдВрдЪрд╛рдПрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдЬреЛрдЦрд┐рдо рд╣реИ рдЬрд┐рд╕реЗ рдЖрдк рдереЛрдбрд╝рд╛ рд╕рд░рд▓ рд▓рд┐рдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЧрд▓рдд рд╕рдВрд╕реНрдХрд░рдг рд╣реИред рдЗрд╕ рдХреЛрдб рдХреЗ рд▓рд┐рдП - рдпрд╣ рднреА рд╕рдм рдХреБрдЫ рд╕рд╣реА рдирд╣реАрдВ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╡рд╣ fdx рдХреЙрд▓ рдкрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП int * :: рдкрд░рдорд╛рдгреБ рдХреЗ рдЖрдВрддрд░рд┐рдХ рдЙрдкрдХрд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рдзрд╛рд░рдгрд╛ рдмрдирд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдЖрдорддреМрд░ рдкрд░ рдорд╛рдорд▓рд╛ рдирд╣реАрдВ рд╣реИред рдХреЛрдб рд▓рд┐рдирдХреНрд╕ x64 рдкрд░ рд╕рдВрдХрд▓рд┐рдд рдФрд░ рдЪрд▓рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрдиреНрдп рдкреНрд▓реЗрдЯрдлрд╛рд░реНрдореЛрдВ рдХреЗ рд╕рд╛рде рд╕рдВрдЧрддрддрд╛ рдХреА рдХреЛрдИ рдЧрд╛рд░рдВрдЯреА рдирд╣реАрдВ рд╣реИред рдЗрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдкрд░рдорд╛рдгреБрдУрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдирд┐рд░реНрднрд░рддрд╛ рдкрд░рдд рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЪреВрдБрдХрд┐ рдпрд╣ рдЗрд╕ рд▓реЗрдЦ рдХрд╛ рд╡рд┐рд╖рдп рдирд╣реАрдВ рд╣реИ (рдФрд░ рдЗрд╕рд▓рд┐рдП рднреА рдХрд┐ рдпрд╣ рдмрд╣реБрдд рд╣реА рдХрдо рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рдЖрдк рдЙрд╕реА C ++ рдореЙрдбреНрдпреВрд▓ рдореЗрдВ рдлрд╝реНрдпреВрдЯреЗрдХреНрд╕ рдХреЛ рдорд┐рд▓рд╛рдПрдВрдЧреЗ) рд╣рдо рдЗрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдЫреЛрдбрд╝ рджреЗрдВрдЧреЗред рдпрд╣ рд╕рд┐рд░реНрдл рдПрдХ рдкреНрд░рджрд░реНрд╢рди рд╣реИ!

рдЧреНрд▓рд┐рдмреЗрдХ рдореНрдпреВрдЯреЗрдХреНрд╕ рдФрд░ рдирд┐рдореНрди-рд╕реНрддрд░ рдХреЗ рддрд╛рд▓реЗ


рддреЛ рд╣рдо рдЙрд╕ рдмрд┐рдВрджреБ рдкрд░ рдкрд╣реБрдВрдЪ рдЧрдП рдЬрд╣рд╛рдВ glibc POSIX рдереНрд░реЗрдбреНрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдПрдХ рд╣рд┐рд╕реНрд╕рд╛ pthread_mutex_t рдкреНрд░рдХрд╛рд░ рд╣реИред рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдЗрд╕ рд▓реЗрдЦ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдХрд╣рд╛ рдерд╛, рдлреНрдпреВрдЯреЗрдХреНрд╕ рд╡рд╣ рдЪреАрдЬ рдирд╣реАрдВ рд╣реИрдВ рдЬрд┐рд╕рдХреА рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдбреЗрд╡рд▓рдкрд░ рдХреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рд░рдирдЯрд╛рдЗрдо рд▓рд╛рдЗрдмреНрд░реЗрд░реАрдЬрд╝ рдпрд╛ рдЙрдЪреНрдЪ-рд╕реНрддрд░реАрдп рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝реЗрд╢рди рдкреНрд░рд╛рдЗрдореЗрдЯрд┐рд╡реНрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕ рд╕рдВрджрд░реНрдн рдореЗрдВ, рдПрдирдкреАрдЯреАрдПрд▓ рдХреЗ рд▓рд┐рдП рдореНрдпреВрдЯреЗрдХреНрд╕ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рджреЗрдЦрдирд╛ рджрд┐рд▓рдЪрд╕реНрдк рд╣реИред Glibc рдХреЛрдб рдореЗрдВ, рдпрд╣ nptl / pthread_mutex_lock.c рдлрд╝рд╛рдЗрд▓ рд╣реИред

рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ рдореНрдпреВрдЯреЗрдХреНрд╕ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдХрд╛рд░рдг рдХреЛрдб рдХрд╛рдлреА рдЬрдЯрд┐рд▓ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рд╡рд╛рдВрдЫрд┐рдд рд╣реЛрдиреЗ рдкрд░ рдХрд╛рдлреА рдкрд░рд┐рдЪрд┐рдд рдмреНрд▓реЙрдХ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВред рдЖрдк sysdeps / unix / sysv / linux / x86_64 / lowlevellock.h рдФрд░ nptl / lowlevellock.c рдлрд╛рдЗрд▓реЛрдВ рдкрд░ рднреА рдирдЬрд╝рд░ рдбрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВред рдХреЛрдб рдХреБрдЫ рднреНрд░рд╛рдордХ рд╣реИ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рддреБрд▓рдирд╛-рдФрд░-рд╡рд┐рдирд┐рдордп рдФрд░ рдлрд╝реБрдЯреЗрдХреНрд╕ рдХреЙрд▓ рдХрд╛ рд╕рдВрдпреЛрдЬрди рдЖрд╕рд╛рди рд╣реИред

рд╕рд┐рд╕реНрдЯреАрдбреНрд╕ / nptl / lowlevellock.h рдлрд╝рд╛рдЗрд▓ рдХреА рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЯрд┐рдкреНрдкрдгреА рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╕рдордЭ рдореЗрдВ рдЖ рдЬрд╛рдиреА рдЪрд╛рд╣рд┐рдП:

 /* Low-level locks use a combination of atomic operations (to acquire and release lock ownership) and futex operations (to block until the state of a lock changes). A lock can be in one of three states: 0: not acquired, 1: acquired with no waiters; no other threads are blocked or about to block for changes to the lock state, >1: acquired, possibly with waiters; there may be other threads blocked or about to block for changes to the lock state. We expect that the common case is an uncontended lock, so we just need to transition the lock between states 0 and 1; releasing the lock does not need to wake any other blocked threads. If the lock is contended and a thread decides to block using a futex operation, then this thread needs to first change the state to >1; if this state is observed during lock release, the releasing thread will wake one of the potentially blocked threads. .. */ 

рд░рдирдЯрд╛рдЗрдо рдлреНрдпреВрдЯреЗрдХреНрд╕


рд░реЗрдВрдЯрд╛рдЗрдо рдЧреЛ рд▓рд┐рдмрд╛рд╕ (рдЬреНрдпрд╛рджрд╛рддрд░ рдорд╛рдорд▓реЛрдВ рдореЗрдВ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдпрд╣ рдкреЛрд╕рд┐рдХреНрд╕ рдереНрд░реЗрдбреНрд╕ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рднрд░реЛрд╕рд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдмрдЬрд╛рдп, рдпрд╣ рд╕реАрдзреЗ рддреМрд░ рдкрд░ рдирд┐рдЪрд▓реЗ рд╕реНрддрд░ рдХреА рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдЗрд╕реЗ рдлреНрдпреВрдЯреЗрдХреНрд╕ рдХреЗ рдЙрдкрдпреЛрдЧ рдХрд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ pthread_mutex_t рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрдкрдХреЛ рдЕрдкрдирд╛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ред рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЖрдЗрдП рд╕рд┐рдВрдХ рд╕реЗ рд╢реБрд░реВ рдХрд░реЗрдВред рдореНрдпреВрдЯреЗрдХреНрд╕ рдкреНрд░рдХрд╛рд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рджрд┐рдЦрд╛рдИ рджреЗрддрд╛ рд╣реИ (src / sync / mutex .go) рдореЗрдВред

рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХрд╛ рд▓реЙрдХ рддрд░реАрдХрд╛ рд▓реЙрдХ рдХреЛ рдЬрд▓реНрджреА рдкрдХрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░рдорд╛рдгреБ рд╕реНрд╡реИрдк рдСрдкрд░реЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдпрд╣ runtime_SemacquireMutex рдХрд╣рддрд╛ рд╣реИ, рдЬреЛ рд░рдирдЯрд╛рдЗрдо рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди src / runtime / lock_futex.go рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдпрд╣ рдХрдИ рд╕реНрдерд┐рд░рд╛рдВрдХ рдХреА рдШреЛрд╖рдгрд╛ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдЖрдкрдХреЗ рд▓рд┐рдП рдкрд░рд┐рдЪрд┐рдд рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ:

 const ( mutex_unlocked = 0 mutex_locked = 1 mutex_sleeping = 2 ... ) // Possible lock states are mutex_unlocked, mutex_locked and mutex_sleeping. // mutex_sleeping means that there is presumably at least one sleeping thread. 

runtime.lock рднреА рдкрд░рдорд╛рдгреБ рдХрд╛рд░реНрдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓реЙрдХ рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реИред рдпрд╣ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ, рдЪреВрдВрдХрд┐ рд░рдирдЯрд╛рдЗрдо.рд▓реЙрдХ рдХреЛ рдЧреЛ рд░рдирдЯрд╛рдЗрдо рдХреЗ рдХрдИ рд╕реНрдерд╛рдиреЛрдВ рдореЗрдВ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ рдкрд░рдорд╛рдгреБ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рджреЛ рд▓рдЧрд╛рддрд╛рд░ рдХреЙрд▓ рдХреЛ рд╣рдЯрд╛рдХрд░ рдХреЛрдб рдХреЛ рдСрдкреНрдЯрд┐рдорд╛рдЗрдЬрд╝ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛, рдЬрдм рд░рдирдЯрд╛рдЗрдо рдХреЙрд▓ рдХрд░реЗрдВред Mutex .lock рд╕реЗред

рдпрджрд┐ рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо-рдЖрд╢реНрд░рд┐рдд рдлрд╝рдВрдХреНрд╢рди futexsleep рдХреЛ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ src / runtime / os_linux.go рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд▓рд┐рдирдХреНрд╕ рдХреЗ рд▓рд┐рдП рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди FUTEX_WAIT_PRIVATE рдХреЛрдб рдХреЗ рд╕рд╛рде рдПрдХ futex рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИ (рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рдЙрдкрдпреБрдХреНрдд рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЧреЛ рд░рдирдЯрд╛рдЗрдо рдПрдХ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рд░рд╣рддрд╛ рд╣реИ)ред

Source: https://habr.com/ru/post/hi418705/


All Articles