Сейчас на форуме: hgdagon, asfa (+4 невидимых)

 eXeL@B —› Программирование —› Синхронизация потоков
Посл.ответ Сообщение


Ранг: 990.2 (! ! !), 380thx
Активность: 0.680
Статус: Модератор
Author of DiE

Создано: 14 мая 2007 18:43 · Поправил: Hellspawn
· Личное сообщение · #1

Вот наконец освободился, решил курсач накодить.

Вообщем задача такая, сихронизация потоков:
- есть сервер к нему коннектятся клиенты, их два типа:
- клиенты, которые читают инфу
- клиенты, которые записывают инфу
Ну и необходимо это всё закодить без косяков. Я сделал на потоках и сокетах.
Т.е. коннектиться клиент, создаём поток, назначаем обработчики, ждём...
Так или иначе нам надо либо отослать инфу из буфера, либо принять и записать в буфер.
Надо защитить от стандартных ошибок.

Терь вопрос, как лучше всего это реализовать (синхронизацию)?
з.ы. мне больше всего приглянулись критические секции...

-----
[nice coder and reverser]




Ранг: 495.3 (мудрец)
Активность: 0.30
Статус: Участник

Создано: 14 мая 2007 19:11
· Личное сообщение · #2

А под какую платформу?
Под NT, как вариант, почитай в MSDN про "Named Pipes".
Эта фигня вообще-то переползла из OS/2 случайным образом, но работает.
ЗЫ Если я вообще правильно понял вопрос.

-----
Всем привет, я вернулся





Ранг: 990.2 (! ! !), 380thx
Активность: 0.680
Статус: Модератор
Author of DiE

Создано: 14 мая 2007 19:18 · Поправил: Hellspawn
· Личное сообщение · #3

Bitfry пишет:
ЗЫ Если я вообще правильно понял вопрос.


ну несколько потоков будут постоянно вызывать процедуру - DoWork(const action:integer)
в которой решается что собственно делать отдать данные клиенту, записать данные в буфер,
отказать клиенту, т.к. буфер переполнен или данных нет вообoе. Вот тут то и нужна синхронизация.

з.ы. самое главное - сообщения не могут быть потеряны

-----
[nice coder and reverser]





Ранг: 85.4 (постоянный)
Активность: 0.080
Статус: Участник

Создано: 14 мая 2007 19:24 · Поправил: Icelot
· Личное сообщение · #4

66.102.9.104/search?q=cache:qxT8J4tjpswJ:www.williamspublishing.com/PDF/5-8459-0879-5/content.pdf+%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F+%D0%B8%D0%BC%D0%B5%D0%BD%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D1%85+%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%B2&hl=ru&ct=clnk&cd=7&gl=ru
не уверен, но вдруг поможет (главы 7-8)
Там вверху указатель на пдф если я правильно понял. Ридер не стоит.

-----
radio uno in ibisa ...




Ранг: 162.2 (ветеран)
Активность: 0.090
Статус: Участник

Создано: 14 мая 2007 19:27
· Личное сообщение · #5

Hellspawn
Критические секции подойдут вполне. Вообще нужно смотреть конкретно что за данные, как читаются, как пишутся и т.п. Рекомендую почитать Рихтера "Создание эффективных WIN32-приложений
с учетом специфики 64-разрядной версии Windows" - там хорошо про синхронизацию написано. Книга есть в сети.



Ранг: 19.0 (новичок)
Активность: 0.010
Статус: Участник

Создано: 14 мая 2007 19:35
· Личное сообщение · #6

Hellspawn пишет:
Так или иначе нам надо либо отослать инфу из буфера, либо принять и записать в буфер.

Поскольку надо защитить только общий буфер от одновременного чтения/записи, то самый простой способ - обернуть операции работы с буфером в критические секции.




Ранг: 990.2 (! ! !), 380thx
Активность: 0.680
Статус: Модератор
Author of DiE

Создано: 14 мая 2007 20:02
· Личное сообщение · #7

amely пишет:
бернуть операции работы с буфером в критические секции.


пасиб, я так и думал что это самое то) тока не совсем понятно, как именно оборачивать...
при старте проги:

InitializeCriticalSection(CriticalSection);

дальше, допустим так, поток N:
...
EnterCriticalSection(CriticalSection);
try
If (action = BUF_READ) then s:=ReadBuf();
If (action = BUF_WRITE) then WriteBuf(s);
finally
LeaveCriticalSection(CriticalSection)
end;


так норм?
...

-----
[nice coder and reverser]





Ранг: 2014.5 (!!!!), 1278thx
Активность: 1.340.25
Статус: Модератор
retired

Создано: 14 мая 2007 20:46
· Личное сообщение · #8

Hellspawn
Должно быть норм.




Ранг: 260.9 (наставник)
Активность: 0.120
Статус: Участник
John Smith

Создано: 14 мая 2007 21:34
· Личное сообщение · #9

Крит секции говорят медленные. Для сокетов пол большей части используются Events (SetEvent) и WaitForSingle(Multiply)Object(s). Вроде так. кодил давно это, так что орфография храмает

-----
Недостаточно только получить знания:надо найти им приложение




Ранг: 162.2 (ветеран)
Активность: 0.090
Статус: Участник

Создано: 14 мая 2007 21:46
· Личное сообщение · #10

Rascal То же подойдёт:
CreateEvent
WaitForSingleObject
PulseEvent

Кстати если есть 2 потока, которые хотят только читать, то их не стоит блокировать. Тут можно посмотреть в сторону функций Interlocked(bla bla bla), или теми же событиями обойтись




Ранг: 387.4 (мудрец)
Активность: 0.170
Статус: Участник
системщик

Создано: 15 мая 2007 01:09
· Личное сообщение · #11

Hellspawn, разбиваешь всё на несколько кусков:

1) протокол: например ASCII команды типа "write ID VALUE" типа "write USERS 1234"

2) клиент: на сокетах и win32 API: socket(), connect(), send()

3) сервер: GUI и один поток в котором всё крутится вокруг select(). Ему скармливаешь все сокеты, и потом обрабатываешь два типа событий: новое соединение (делаешь accept()) и RX на уже существующем (делаешь recv() и парсишь данные)

Усё. Никаких там critical sections, events, wait for multiple objects....

P.S. Rascal не неси чепухи. Сначала напиши test case, воткни QueryPerformanceCounter() и померяй.



Ранг: 162.2 (ветеран)
Активность: 0.090
Статус: Участник

Создано: 15 мая 2007 05:18
· Личное сообщение · #12

s0larian пишет:
Усё. Никаких там critical sections, events, wait for multiple objects....


Угу. Нафига вообще потоки придумали. Если рассуждать как ты, то любую прогу можно однопоточной сделать.




Ранг: 387.4 (мудрец)
Активность: 0.170
Статус: Участник
системщик

Создано: 15 мая 2007 05:36
· Личное сообщение · #13

asd пишет:
Нафига вообще потоки придумали. Если рассуждать как ты, то любую прогу можно однопоточной сделать.

Потоки реально нужны в нескольких случаях:
- когда можно что-то распаралелить и получить повышенную скорость при наличии нескольких ядер
- упростить структуру софта в ситуации когда софтина может скажем, обрабатывать много запросов очень быстро, и паралельно медленно что-нить записывать на диск.

Ессно всё что угодно можно написать с одним потоком, таймерами и очередями, я это не предлагаю. Но, в случае простого сервера который, скажем, позволяет читать что-то из мелкой DB потоки не нужны - они всё равно будут ждать доступа к этой DB где будут locks.

А использовать потоки "потому что они есть, и это круто" - это маразм. Думать надо, и смотреть - есть ли от этого польза.



Ранг: 162.2 (ветеран)
Активность: 0.090
Статус: Участник

Создано: 15 мая 2007 06:27
· Личное сообщение · #14

s0larian
Думать всегда нужно, конечто, только это, имхо, как раз тот случай, когда выйгрыш мы получим почти в любой ситуации.

Ну и 2-ое - этож курсач, сказали синхронизировать, так синхронизируй, а не умничай)




Ранг: 387.4 (мудрец)
Активность: 0.170
Статус: Участник
системщик

Создано: 15 мая 2007 08:52 · Поправил: s0larian
· Личное сообщение · #15

asd, ёлки, ну, объясни мне, где будет выйгрыш если у тебя поток для каждого сокета и данные читаются/пишутся из какой-нить базёнки где первое выражение каждой функции lock() ? Ты вообще понимаешь как работают потоки и примитивы синхронизации?



Ранг: 162.2 (ветеран)
Активность: 0.090
Статус: Участник

Создано: 15 мая 2007 09:36
· Личное сообщение · #16

s0larian
Скажи мне, почему ты считаешь:
1)что мы работаем с базой данных, а не просто с областью памяти.(Ну хрен с ней пусть и с базой)
2)что сервер не должен производить каких либо длительных вычислений.
3)что сервер в конце концов одноядерный.

С чего такая нелюбовь к синхронизации?



Ранг: 60.4 (постоянный)
Активность: 0.030
Статус: Участник

Создано: 15 мая 2007 10:20
· Личное сообщение · #17

Джонсон М. Харт. Системное программирование в среде Win32: Пер. с англ. – 2-е изд. –М.: Вильямс, 2001.-464с.: ил.

Путёвая книга на тему. Где-то в Сети был электронный вариант, причём более свежее издание (Win64). Там много про синхронизацию говорится.



Ранг: 203.3 (наставник)
Активность: 0.220
Статус: Участник
UPX Killer -d

Создано: 15 мая 2007 13:33
· Личное сообщение · #18

Hellspawn, вот схожая ветка, может пригодится что...
http://exelab.ru/f/action=vthread&forum=6&topic=7759

-----
Я медленно снимаю с неё UPX... *FF_User*




Ранг: 19.0 (новичок)
Активность: 0.010
Статус: Участник

Создано: 15 мая 2007 16:12
· Личное сообщение · #19

Hellspawn пишет:
при старте проги:

InitializeCriticalSection(CriticalSection);

дальше, допустим так, поток N:
...
EnterCriticalSection(CriticalSection);
try
If (action = BUF_READ) then s:=ReadBuf();
If (action = BUF_WRITE) then WriteBuf(s);
finally
LeaveCriticalSection(CriticalSection)
end;

так норм?


нормально, но еще добавить DeleteCriticalSection при выходе из проги

PS: примитивов синхронихации потоков есть большое множество, но имхо самый простой способ в данном случае - это критические секции.




Ранг: 990.2 (! ! !), 380thx
Активность: 0.680
Статус: Модератор
Author of DiE

Создано: 15 мая 2007 16:39 · Поправил: Hellspawn
· Личное сообщение · #20

ух написали то) в общем у меня походу при данной реализации не будет конфликтов, но
я всё равно обернул в секции критицеские участки программы, чуть позже может даже выложу,
то что получилось , но тока когда сдам

-----
[nice coder and reverser]





Ранг: 260.9 (наставник)
Активность: 0.120
Статус: Участник
John Smith

Создано: 15 мая 2007 17:21
· Личное сообщение · #21

s0larian
на сколько я помню сокеты есть синхронные и асинхронные. синхронные - поток останавливается до, например, получения данных recv. Интерфейс, на сколько я понимаю, не работает по понятным причинам.
На счёт секций
Rascal пишет:
Крит секции говорят медленные

Не я говорю. Кто то говорил. Я не тестил. Это было сказано больше для подтверждения или опровержения. Поэтому слова "не неси чепухи" я считаю неуместными

-----
Недостаточно только получить знания:надо найти им приложение





Ранг: 387.4 (мудрец)
Активность: 0.170
Статус: Участник
системщик

Создано: 15 мая 2007 20:07
· Личное сообщение · #22

asd, ты о пять не о том. Я привёл пример, который, как мне кажется, близок к тому что пишет Hellspawn. В моём примере, если писать имеено так как я упомянул, всё выльется в то что только один поток обращается к данным (к базе) в любой момент времяни. То есть, все потоки которые получают данные паралельно, всё равно превращаются в один из-за синхронизации. Так зачем тогда делать синхронизацию и потоки?

Повторюсь, я не говорю что потоки вообще не нужны. Я говорю что если решение напоминает вышеописанный сценарий, то толку от потоков ноль, и есть потраченное время на реализацию и отладку.



Ранг: 162.2 (ветеран)
Активность: 0.090
Статус: Участник

Создано: 15 мая 2007 21:40
· Личное сообщение · #23

s0larian пишет:
всё выльется в то что только один поток обращается к данным (к базе) в любой момент времяни. То есть, все потоки которые получают данные паралельно, всё равно превращаются в один из-за синхронизации. Так зачем тогда делать синхронизацию и потоки?


Для того, чтобы можно было параллельно обрабатывать/подготавливать полученные данные. По мне так это просто удобно.




Ранг: 387.4 (мудрец)
Активность: 0.170
Статус: Участник
системщик

Создано: 15 мая 2007 22:07
· Личное сообщение · #24

asd пишет:
s0larian пишет:
всё выльется в то что только один поток обращается к данным (к базе) в любой момент времяни. То есть, все потоки которые получают данные паралельно, всё равно превращаются в один из-за синхронизации. Так зачем тогда делать синхронизацию и потоки?

Для того, чтобы можно было параллельно обрабатывать/подготавливать полученные данные. По мне так это просто удобно.

I rest my case




Ранг: 109.2 (ветеран)
Активность: 0.090
Статус: Участник
Cardinal

Создано: 15 мая 2007 22:46 · Поправил: tnt17
· Личное сообщение · #25

Hellspawn пишет:
- клиенты, которые читают инфу
- клиенты, которые записывают инфу

тебе еще это нужно учитывать, т.е. походу чтение-запись ведется паралелльно. Ситуация:
Пусть процесс чтение занимает 1 условный такт, запись - 4 такта.
t1: Процесс 1 хочет записать информацию(запись стартует не моментально)
t2: Процесс 2 хочет прочесть информацию.Запись не завершена (осталось 3 такта);
t3: Чтение, остался 1 такт; Запись еще 2 такта.
t4: Чтение завершено;Запись - остался 1 такт
t5: Запись завершена.
Вот что нужно обмозговать:
1) как в момент когда производиться запись,процессу запросившему чтение вернуть старое значение буфера до окончания процесса записи.Тут именно учитывается продолжительность передачи всей последовательности данных по каналу связи(сеть например)
2) каким образом все это дело синхронизовать.
Можно например создать 2 буффера: 1 на чтение,2 на запись.На них вешаешь 2 семафора(или что там у тебя). Подумай над переносом инфы из одного буффера во второй, там впринципе не сложно, но синхронизировать нужно.
так что - думай ;)

-----
– Почему ты работаешь по ночам ? – Так удобнее... В одну смену с чертями...





Ранг: 387.4 (мудрец)
Активность: 0.170
Статус: Участник
системщик

Создано: 16 мая 2007 03:39 · Поправил: s0larian
· Личное сообщение · #26

Hellspawn пишет:
Вообщем задача такая, сихронизация потоков:
- есть сервер к нему коннектятся клиенты, их два типа:
- клиенты, которые читают инфу
- клиенты, которые записывают инфу

Так енто, как ты хранишь данные? А данные они для каждого клиента свои или все клиенты читают/пишут что-то общее? В первом случае вообще не надо locks, т.к. у каждого клиента свои данные (если для каждого клиента поток)

Во втором, концептуально, тоже очень просто. Скажем, у тебя есть две функции:

void Write(uint32 key, std::string data);
std::string data Read(uint32 key);


Если сервер однопоточный, то locks не надо. Если многопоточный, то вставляешь в обе функции lock() и в конце unlock().

На windows реализовать этот lock() легко через CriticalSection.


 eXeL@B —› Программирование —› Синхронизация потоков
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати