Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Синхронизация с потоком


Автор: Wing 22.4.2006, 18:39
Доброго времени суток. Прочитал материал по синхронизации потоков, там целая тьма способов Event, Mutex, Semaphore... Однако все они также используются для межпроцессной синхронизации, а есть что-нить в пределах одного приложения или можно для такой цели использовать обычные глобальные переменные. 

Автор: Poseidon 22.4.2006, 18:42
Что именно подразумевается под синхронизацией потоков? Что нужно реализовать? У TThread есть куча стандартных методов, нужно только знать, что нужно smile 

Автор: Wing 22.4.2006, 18:56
Есть некоторая прога которая создает поток для некоторой цели, в ходе работы поток передает информацию о своем состоянии в основной поток. Если основной поток занят то второй поток должен продолжить свое выполнение без передачи данных. 
Собственно можно-ли использовать переменную типа Boolean для индикации занят/свободен основного потока. 

Автор: Snowy 22.4.2006, 22:44
Цитата(Wing @  22.4.2006,  18:56 Найти цитируемый пост)
Собственно можно-ли использовать переменную типа Boolean для индикации занят/свободен основного потока. 
Можно, но не стоит.
Почитай про критические секции. (Critical Sections) 

Автор: Sunvas 23.4.2006, 00:28
Цитата(Wing @  22.4.2006,  18:56 Найти цитируемый пост)
 Если основной поток занят

Что ты под этим подразумевашь?
synchronize({имя процедуры}) 

Автор: Wing 23.4.2006, 15:26
Цитата(Sunvas @  23.4.2006,  00:28 Найти цитируемый пост)
Что ты под этим подразумевашь?
synchronize({имя процедуры}) 

Я имею ввиду что поток занят некоторой работой.

Цитата(Snowy @  22.4.2006,  22:44 Найти цитируемый пост)
Можно, но не стоит.
Почитай про критические секции. (Critical Sections) 

Во! Ты меня понял. Как можно такое обойти?  

Автор: Rouse_ 23.4.2006, 15:31
Цитата(Wing @  22.4.2006,  19:56 Найти цитируемый пост)
Если основной поток занят то второй поток должен продолжить свое выполнение без передачи данных. 

создаешь область хранения, к которой должен обратиться основной поток, к примеру тот-же MemoryMappedFile и через PostMesssage отправляешь ему адрес этой области. Когда главный поток освободиться, он примет твое сообщение и прочитает переданные ему данные находящиеся по переданному указателю, чтобы избежать утечек, желательно после прочтения разрушить MMF. 

Автор: Snowy 23.4.2006, 15:48
Цитата(Wing @  22.4.2006,  18:56 Найти цитируемый пост)
Есть некоторая прога которая создает поток для некоторой цели, в ходе работы поток передает информацию о своем состоянии в основной поток. Если основной поток занят то второй поток должен продолжить свое выполнение без передачи данных. 
Для перехода в занятое состояние, главный поток захватывает критическую секцию и начинает работу. Как закончит - освобождает крстическую секцию.
Второй поток хочет передать данные. Он пробует захватить критическую секцию. Если не удалось, значит занято. Работаем дальше. Если не занято - захватывает критическую секцию, пишет данные, освобождает, шлет сообщение главному потоку о том, что данные легли - обрабатывай. Главный захватывает критическую секцию, читает данные, обрабатывает, освобождает... и т.д. 

Автор: Rouse_ 23.4.2006, 18:31
Snowy, ты кудато не сюда. Зачем главному потоку захват критичской секции когда он должен обрабатывать данные пришедшие от дочерних? 

Автор: Wing 23.4.2006, 20:18
Ну допустим такой проект: 

Автор: Rouse_ 23.4.2006, 20:28
Wing, Это в чем юмор вот этого ?

Код

          hMMF := CreateFileMapping($FFFFFFFF, nil, 0, 0, SizeOf(TMyInfoBuffer), 'MyInfoBuffer');
          p := MapViewOfFile(hMMF, 0, 0, 0, SizeOf(TMyInfoBuffer));
          p^.hMMF := hMMF;

По какой книжке так писал? 

Автор: Wing 23.4.2006, 21:37
Цитата(Rouse_ @  23.4.2006,  20:28 Найти цитируемый пост)
Это в чем юмор вот этого ?

Цитата(Rouse_ @  23.4.2006,  15:31 Найти цитируемый пост)
MemoryMappedFile


Цитата(Rouse_ @  23.4.2006,  20:28 Найти цитируемый пост)
По какой книжке так писал? 
Ни по какой. Потому что в той которая есть ни чего полезного нету - стало быть... плохая книжка. 

Писал по памяти + Win32 SDK Reference.



 

Автор: Rouse_ 24.4.2006, 08:59
Блин, или я не правильно обьясняю или одно из двух smile
Смотри пример:

Код

unit Unit9;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

const
  WM_THREAD_NOTIFY = WM_USER + 1;

type
  PTestThreadStructure = ^TTestThreadStructure;
  TTestThreadStructure = packed record
    IntParam: Integer;
    StringParam: ShortString;
  end;

  TForm9 = class(TForm)
    Memo1: TMemo;
    Memo2: TMemo;
    procedure FormShow(Sender: TObject);
  private
    procedure WMThreadNotify(var Message: TMessage); message WM_THREAD_NOTIFY;
  end;

  TTestThread = class(TThread)
  private
    hMainThreadHandle: THandle;
  protected
    procedure Execute; override;
  end;

var
  Form9: TForm9;

implementation

{$R *.dfm}

procedure TForm9.FormShow(Sender: TObject);
var
  I: Integer;
begin
  with TTestThread.Create(True) do
  begin
    FreeOnTerminate := True;
    hMainThreadHandle := Form9.Handle;
    Resume;
  end;
  for I := 0 to $FFFF do
    if (I mod 16) = 0 then
      Memo1.Lines.Add(InttoStr(I));   
end;

procedure TForm9.WMThreadNotify(var Message: TMessage);
var
  AData: TTestThreadStructure;
begin
  AData := PTestThreadStructure(Message.WParam)^;
  Memo2.Lines.Add('Текущее значение в потоке: ' + IntToStr(AData.IntParam) +
    sLineBreak + AData.StringParam);
  UnmapViewOfFile(PTestThreadStructure(Message.WParam));
  CloseHandle(Message.LParam);
end;

{ TTestThread }

procedure TTestThread.Execute;
var
  I: Integer;
  hMMF: THandle;
  AData: TTestThreadStructure;
  pData: PTestThreadStructure;
begin
  for I := 0 to $FF do
    if (I mod 48) = 0 then
    begin
      hMMF := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, 4, nil);
      pData := MapViewOfFile(hMMF, FILE_MAP_WRITE, 0, 0, 0);
      AData.IntParam := I;
      AData.StringParam := 'Осталось обработать ' +
        IntToStr($FF - I) + ' значений';
      pData^ := AData;
      if not PostMessage(hMainThreadHandle, WM_THREAD_NOTIFY,
        Integer(pData), hMMF) then RaiseLastOSError;
    end;
end;

end.


Тут главный поток занят своим делом, паралельно с ним трудиться второй поток, когда главный освободиться он примет все данные от второстепенного smile 

Автор: Wing 25.4.2006, 22:14
Цитата(Rouse_ @  24.4.2006,  08:59 Найти цитируемый пост)
Блин, или я не Паправильно обьясняю или одно из двух 

Хм. Видимо воторое smile
Спасибо.

Однако вопрос был в другом: как сделать флажок для главного потока? Ибо второй поток не должен отправлять данные если первый занят.  

Автор: Rouse_ 26.4.2006, 08:15
Хм, а смысл? Поток всеравно должен гдето буферизировать данные. ИМХО данный вариант который я тебе показал самый оптимальный для тебя, т.к. второй поток не отправляет данные а всего лишь ложит их во времнное хранилище и сигнализирует главному что данные на месте. Когда главный захочет читать - тогда и прочитает..
Главномне обязательно читать сразу по приходу WM_THREAD_NOTIFY, он также может просто запомнить где нибудь у себя указатель на данные, а прочитать их позднее... 

Автор: Демо 27.4.2006, 10:17
Цитата(Wing @  25.4.2006,  22:14 Найти цитируемый пост)
Однако вопрос был в другом: как сделать флажок для главного потока?


Ну это-то как раз самая тривиальная задача. Достаточно ввести Boolean-флаг и проверять его. 

Автор: Wing 27.4.2006, 20:31
Rouse_, видимо я так и поступлю.

Демо, читай выше. 

Автор: Демо 28.4.2006, 09:23
Цитата(Wing @  27.4.2006,  20:31 Найти цитируемый пост)
Демо, читай выше. 


Читал.
Но не вижу никаких проблем в реализации, так как в твоей задачи не нужно ожидание освобождения ресурса. Следовательно, синхронизация нужна самая примитивная.
Для твоей задачи достаточно Boolean-флажков.  

Автор: Wing 29.4.2006, 13:20
 smile 
Демо, нет такое не подходит. До этого я и сам додумался, но иногда вылазиет ошибка о неверном доступе к памяти.

Цитата(Snowy @  22.4.2006,  22:44 Найти цитируемый пост)
Цитата(Wing @  22.4.2006,  18:56 Найти цитируемый пост)
Собственно можно-ли использовать переменную типа Boolean для индикации занят/свободен основного потока. 
Можно, но не стоит.
Почитай про критические секции. (Critical Sections)

 

Автор: Демо 29.4.2006, 17:33
Цитата(Wing @  29.4.2006,  13:20 Найти цитируемый пост)
нет такое не подходит. До этого я и сам додумался, но иногда вылазиет ошибка о неверном доступе к памяти.


Просто нужно очень аккуратно и точно работать с указателями и буфрами для записи и чтения.
Те указатели, которые используются в разных потоках(сами адреса) нужно защитить критической секцией, либо флагами(Boolean, так как их чтение и запись - атомарная операция). 

Автор: Wing 3.5.2006, 21:10
Демо, действительно так тоже можно. ;) 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)