+ All Categories
Home > Documents > Введение в разработку многопоточных приложений

Введение в разработку многопоточных приложений

Date post: 15-Jun-2015
Category:
Upload: custis
View: 391 times
Download: 4 times
Share this document with a friend
Description:
Открытый семинар для студентов в компании CUSTIS (31 октября 2012). Лектор: Дмитрий Костиков, ведущий разработчик C#, сертифицированный специалист Microsoft (MCTS), специалист по разработке корпоративных приложений (С#, SQL, Win/Web). Из этого семинара вы узнаете, почему важно знать принципы работы с многопоточностью. Будет рассмотрена эволюция представлений и методик работы с многопоточностью, описаны проблемы, возникающие при разработке многопоточных приложений, а также механизмы для работы с многопоточностью, применяющиеся в Windows и .NET. Видеозапись семинара: https://vimeo.com/53323987.
Popular Tags:
62
Введение в разработку многопоточных приложений Дмитрий Костиков Ведущий разработчик C# 31 октября 2012 года
Transcript
Page 1: Введение в разработку многопоточных приложений

Введение в разработку многопоточных приложений

Дмитрий Костиков Ведущий разработчик C#

31 октября 2012 года

Page 2: Введение в разработку многопоточных приложений

2/62

Page 3: Введение в разработку многопоточных приложений

Поморгаем int main() { while(true) { EnableLedOne(); DisableLedOne(); } }

3/62

Page 4: Введение в разработку многопоточных приложений

Поморгаем int Delay(int ms) { for(int i = 0; i < ms * k ; i++){} } int main() { while(true) { EnableLedOne(); Delay(300); DisableLedOne(); Delay(900); } } 4/62

Page 5: Введение в разработку многопоточных приложений

Одна лампочка

300 900 300 900 300

t(мс)

5/62

Page 6: Введение в разработку многопоточных приложений

6/62

Page 7: Введение в разработку многопоточных приложений

Две лампочки

7/62

300 900 300 900 300

t(мс)

250 750 250 250 750 750

Page 8: Введение в разработку многопоточных приложений

Две лампочки

300 900 300 900 300

t(мс)

250 750 250 250 750 750

50 мс

8/62

Page 9: Введение в разработку многопоточных приложений

Очередь заданий Task1, через 50мс Task2, через 100мс

Task1, сейчас Task2, через 50мс

Task2, сейчас

t(мс)

0 100 50

9/62

Page 10: Введение в разработку многопоточных приложений

Поморгаем с планировщиком void EnableLedOneTask() { EnableLedOne(); RegisterDelayedTask(DisableLedOneTask, 300); } void DisableLedOneTask() { DisableLedOne(); RegisterDelayedTask(EnableLedOneTask, 900); } int main() { RegisterDelayedTask(EnableLedOneTask, 0); RegisterDelayedTask(EnableLedTwoTask, 0); while(true) { Delay(50); ExecuteTaskByTime(); } }

10/62

Page 11: Введение в разработку многопоточных приложений

Sleep void LedOne () { while(true) { EnableLedOne(); Sleep(300); DisableLedOne(); Sleep(600); } }

11/62

Page 12: Введение в разработку многопоточных приложений

Sleep void LedOneThread() { B202 while(true) B203 { B204 EnableLedOne(); B205 Sleep(300); B207 DisableLedOne(); B208 Sleep(600); B209 } }

12/62

Page 13: Введение в разработку многопоточных приложений

Sleep void LedOneThread() { int i = GetOnTime(); int j = GetOffTime(); while(true) { EnableLedOne(); Sleep(i); DisableLedOne(); Sleep(j); } }

13/62

Page 14: Введение в разработку многопоточных приложений

Стек и регистры

j

Регистры

Стек

i

14/62

Page 15: Введение в разработку многопоточных приложений

Стек и регистры

Стек

h j

15/62

Регистры

g

Page 16: Введение в разработку многопоточных приложений

Стеки и регистры

Регистры

i

j

Стек потока 1

i

16/62

Page 17: Введение в разработку многопоточных приложений

Стеки и регистры

Регистры

Стек потока 2

g

h j

Стек потока 1

i g

17/62

Page 18: Введение в разработку многопоточных приложений

Поток Физически – процедура потока, служебные

данные и стек

Логически – виртуальный процессор

18/62

Page 19: Введение в разработку многопоточных приложений

Типы многопоточности

Sleep()

Sleep()

Поток 1 Поток 2

t t

19/62

Page 20: Введение в разработку многопоточных приложений

Типы многопоточности

Кванты

Sleep()

Поток 2

t t

Квант кончился

Квант кончился

20/62

Поток 1

Page 21: Введение в разработку многопоточных приложений

Создание потоков .NET: class Thread WinAPI: CreateThread/TerminateThread

static void Main(string[] args) { Thread thread = new Thread(DoA); thread.Start(); } static void DoA() { … }

21/62

Page 22: Введение в разработку многопоточных приложений

Пул потоков WinAPI: QueueUserWorkItem .NET: class ThreadPool

static void Main(string[] args) { ThreadPool.QueueUserWorkItem(DoA); } static void DoA(object state) { }

22/62

Page 23: Введение в разработку многопоточных приложений

23/62

Page 24: Введение в разработку многопоточных приложений

24/62

Page 25: Введение в разработку многопоточных приложений

GUI void OnClick() { ThreadPool.QueueUserWorkItem(DoA); } void DoA(object state) { resultTextBox.Text = ComputeSmth(); }

25/62

Page 26: Введение в разработку многопоточных приложений

GUI

Очередь сообщений

Поток окна

Перерисуй окно

Кликнули мышкой

26/62

Page 27: Введение в разработку многопоточных приложений

GUI

Очередь сообщений

Поток окна

Перерисуй окно

Кликнули мышкой

Обработай окончание

вычисления

27/62

Page 28: Введение в разработку многопоточных приложений

GUI static void DoA(object state) { _result = ComputeSmth(); resultTextBox.BeginInvoke(SetResult); } static void SetResult (object state) { resultTextBox.Text = _result; } 28/62

Page 29: Введение в разработку многопоточных приложений

29/62

Page 30: Введение в разработку многопоточных приложений

Проблемы многопоточности Проблемы корректности

Проблемы живучести

30/62

Page 31: Введение в разработку многопоточных приложений

Состояние гонки _i++; MOV EAX , [_ i ] INC EAX MOV [ _i ] , EAX

31/62

Page 32: Введение в разработку многопоточных приложений

«Одновременное» выполнение Поток 1

MOV EAX , [ i ]

INC EAX

MOV [ i ] , EAX

Поток 2

MOV EAX , [ i ]

INC EAX

MOV [ i ] , EAX

t

32/62

Page 33: Введение в разработку многопоточных приложений

Многопроцессорная машина

Процессор 1 Процессор 2

Память

Кэш 1 Кэш 2

i = 2 i = 2 i = 3 i = 3

33/62

i = 2 i = 2 i = 3 i = 3

Page 34: Введение в разработку многопоточных приложений

Многопроцессорная машина

Процессор 1 Процессор 2

Память

Кэш 1 Кэш 2

i = 2 i = 2

i = 2 i = 2 i = 3 i = 3

i = 3 i = 3

Когерентность кэша

34/62

Page 35: Введение в разработку многопоточных приложений

Последовательное выполнение Поток 1

Enter() MOV EAX , [ i ] INC EAX MOV [ i ] , EAX Exit()

Поток 2

Enter() INC EAX MOV EAX , [ i ] MOV [ i ] , EAX t

35/62

Page 36: Введение в разработку многопоточных приложений

Критический регион

… EnterCriticalRegion() _i++; LeaveCriticalRegion() …

36/62

Page 37: Введение в разработку многопоточных приложений

Критический регион int taken = 0; void EnterCriticalRegion() { while(taken != 0) {} taken = 1; } void LeaveCriticalRegion() { taken = 0; }

37/62

Page 38: Введение в разработку многопоточных приложений

38/62

Page 39: Введение в разработку многопоточных приложений

Строгое чередование const int N = 2; int turn = 0; void EnterCriticalRegion (int i) { while (turn != i ) {} } void LeaveCriticalRegion (int i) { turn = (i + 1) % N; }

39/62

Page 40: Введение в разработку многопоточных приложений

Алгоритм Петерсона (1981) bool flags[2]; int turn = 0; void EnterCriticalRegion (int i) { flags [ i ] = true ; turn = 1 - i ; while ( flags[1 - i] && turn != i ) {} } void LeaveCriticalRegion (int i) { flags [i] = false; }

40/62

Page 41: Введение в разработку многопоточных приложений

CAS long CompareExchange(long *Destination, long Exchange, long Comparand); int taken = 0; void EnterCriticalRegion() { while( CompareExchange((&taken ,1 , 0)) {} } void LeaveCriticalRegion() { taken = 0; }

41/62

Page 42: Введение в разработку многопоточных приложений

Interlocked Interlocked.Increment(ref _i);

42/62

Page 43: Введение в разработку многопоточных приложений

Mutex static Mutex _mutex = new Mutex();

static void DoA(object state)

{

_mutex.WaitOne();

_i++;

_mutex.ReleaseMutex();

}

43/62

Page 44: Введение в разработку многопоточных приложений

Monitor void EnterCriticalRegion()

{

for(int i = 0; i < 1000 &&

! CompareExchange((&taken ,1 , 0)) ; i++)

{}

if(taken == 0)

{

_mutex.WaitOne();

}

}

44/62

Page 45: Введение в разработку многопоточных приложений

Monitor private static object _lockObject; static void DoA(object state) { lock(_lockObject) { ThreadUnsafeOperation(); } } WinAPI: EnterCriticalSection/LeaveCriticalSection

45/62

Page 46: Введение в разработку многопоточных приложений

Неблокирующая синхронизация

46/62

Page 47: Введение в разработку многопоточных приложений

Фокус flags[i] = true;

turn = 1 - i;

while (flags[1 - i] && turn != i)

{ }

47/62

Page 48: Введение в разработку многопоточных приложений

Фокус flags[i] = true;

turn = 1 - i;

int tmp1 = flags[1 - i]

int tmp2 = turn != I

48/62

Page 49: Введение в разработку многопоточных приложений

Фокус flags[i] = true;

int tmp1 = flags[1 - i]

49/62

Page 50: Введение в разработку многопоточных приложений

Фокус

50/62

CPU1

flags[0] = true; int tmp1 = flags[1] …

CPU2

flags[1] = true; int tmp1 = flags[0] …

Page 51: Введение в разработку многопоточных приложений

Фокус

CPU1

flags[0] = true; int tmp1 = flags[1] …

CPU2

flags[1] = true; int tmp1 = flags[0] …

51/62

Page 52: Введение в разработку многопоточных приложений

Многопроцессорная машина

Процессор 1 Процессор 2

Память

Кэш 1 Кэш 2 flags[0] = true

flags[1] = true

flags[0]=0 flags[1]=0

flags[0]=0 flags[1]=0

52/62

Page 53: Введение в разработку многопоточных приложений

Фокус int tmp1 = flags[1 - i]

flags[i] = true;

53/62

Page 54: Введение в разработку многопоточных приложений

Memory barrier flags[i] = true;

Thread.MemoryBarrier();

int tmp1 = flags[1 - i]

54/62

Page 55: Введение в разработку многопоточных приложений

Lock flags[i] = true; turn = 1 - i; lock (_object) { while (flags[1 - i] && turn != i) { } }

55/62

Page 56: Введение в разработку многопоточных приложений

56/62

Page 57: Введение в разработку многопоточных приложений

Deadlock public static void Transfer(BankAccount a, BankAccount b, decimal amount) { lock (a) { if (a.m_balance < amount) throw new Exception("Insufficient funds."); lock (b) { a.m_balance -= amount; b.m_balance += amount; } } } 57/62

Page 58: Введение в разработку многопоточных приложений

Deadlock

Поток 1

Поток 2

Lock(счет1)

Lock(счет2)

Lock(счет2)

Lock(счет1) t

58/62

Page 59: Введение в разработку многопоточных приложений

Банковский алгоритм public static void Transfer(BankAccount a, BankAccount b, decimal amount) { LockManager.LockAccounts(a, b) if (a.m_balance < amount) throw new Exception("Insufficient funds."); a.m_balance -= amount; b.m_balance += amount; } 59/62

Page 60: Введение в разработку многопоточных приложений

Сортировка

Поток 1

Поток 2

Lock(счет1) Lock(счет2)

Lock(счет1) Lock(счет2) t

60/62

Page 61: Введение в разработку многопоточных приложений

Что почитать Concurrent Programming on Windows

(Joe Duffy)

http://www.albahari.com/threading/

CLR via C# (Jeffrey Richter)

http://habrahabr.ru/users/rumatavz

Memory Barriers: a Hardware View for Software Hackers

61/62

Page 62: Введение в разработку многопоточных приложений

Спасибо! Вопросы?

Дмитрий Костиков [email protected]

62/62


Recommended