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


Автор: valerchi 31.8.2014, 12:28
Мужики, объясните, что происходит... Имею два потока в одном идёт цикл и счётчик записывается в буфер обмена. В другом потоке идёт считывание из буфера обмена и вывод результата в Memo.
После записи в Мемо нескольких чисел вылетает такая ошибка, что делфи вообще глючит, а буфер обмена не работает.
Вот мой код, первый поток:
Код

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Fslu:slu;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
begin
i:=0;
repeat
inc(i);
if Clipboard.AsText <> '' then
begin
Clipboard.Open;
Memo1.SelText := Clipboard.AsText;
Clipboard.Close;
end;
until i=1000;
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
Fslu := slu.Create(False);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 Fslu.Terminate;
   Fslu.Free;
end;

end.

И второй поток
Код

unit Unit2;

interface

uses
  Classes,clipbrd,Messages, SysUtils, Variants, Graphics, Controls, Forms;

type
  slu = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

implementation

{ Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,

      Synchronize(UpdateCaption);

  and UpdateCaption could look like,

    procedure slu.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }

{ slu }

procedure slu.Execute;
var i:integer; g:string;
begin
i:=0;
repeat
inc(i);
if i=53 then
i:=1;
g:=inttostr(i);
Clipboard.Open;
Clipboard.AsText:=g+' ';
Clipboard.Close;
until i=53;

end;

end.
 

Автор: kami 31.8.2014, 20:59
1. как минимум странно использовать в качестве средства обмена между потоками буфер обмена.
2. Clipboard - синглтон, причем (емнип) не потокобезопасный. Посему - считайте его VCL компонентом, со всеми вытекающими в виде желательной работы через Synchronize. Отсюда могут и глюки расти. А использование Synchronize в контексте приведенного кода полностью сводит на нет все разделение на потоки.
Может, обрисуете задачу? Решение выглядит как из неисправной пушки по воробьям...

Автор: valerchi 31.8.2014, 21:43
Раньше я делал почти так же, только вместо записи в буфер обмена, второй поток записывал результат не в буфер, а в файл, а первый поток считывал информацию из файла, (Своего рода генератор случайных чисел) но это было слишком медленно. Хочу поэкспериментировать, сделать гсч таким образом (с помощью буфера обмена).

Автор: Poseidon 1.9.2014, 00:39
Буфер обмена - это территория пользователя. Лезть на эту территорию без разрешения - очень не хорошо. Для синхронизации потоков есть достаточное количество инструментов. http://forum.vingrad.ru/forum/topic-60076.html достаточно хорошо описаны средства синхронизации потоков. Делать это через буфер обмена ой как не правильно. 

Автор: drkot 13.9.2014, 13:42
Кроме того, что уже сказано, о плохом тоне такого подхода... могу добавить только причину "глюка".


Первый поток открывает буфер
Второй поток открывает буфер (он уже открыт, по сути ничего не происходит)
Второй поток пишет в буфер
Второй поток закрывает буфер
Первый поток читает из буфера (а он уже закрыт, отсюда и глюк)

Решение: обернуть работу с буфером в критическую секцию, а учитывая что это TObject, то логичнее использовать TMonitor 

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