Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Загрузка проца 100% после закрытия потока 
:(
    Опции темы
Specialistvlad
Дата 20.10.2010, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 20.10.2010

Репутация: нет
Всего: нет



Всем привет. С потоками раньше не работал, пытаюсь первый раз. Загуглив ответа не нашел.
В общем пишу некоторую программу, для работы с УСБ. 
Задача такая: при подключении устройства определить нужно оно или нет, если нужное - то создать поток для него(пока максимум один). Вот тут и начинаются проблемы. У меня почему в диспетчере задач показывает после создания потока их кол-во не 2, а 3! Может так и должно быть это ладно. Вроде бы все работает. Но после того как я при отключении устройства хочу пректратить поток он закрывается и резко загрузка процессора становится 100%. В диспетчере вижу, что кол-во потоков теперь не 3, а 2.

И сами вопросы. Почему при запуске приложения 1 поток, а когда создаю еще один их становится 3.  :щацко Вроде бы после 1 идет 2. И почему загрузка процессора максимальная? Ткните в ошибку плз.

Лог работы на скрине.
user posted image

Код программы:
Код
    
    
TNewThread = class(TThread)
    private
        logtext:string;
        procedure AddToLog();
    protected
        procedure Execute; override;
    end;

var
    Form1:     TForm1;
    cncdev:        TCNCDevice;   
    devThread:    TNewThread;
    Online:    boolean=false;
    busy:      boolean=false;
                                        
    const MyDeviceProductName = 'Universal CNC Controller';
    const MyDeviceVendorID = $04D8;
    const MyDeviceProductID = $003F;

    const PCCOMM_GET                         = 10;
    const PCCOMM_SET                         = 20;
    const PCCOMM_GETVERSION             = 30;
    const PCCOMM_GOTOBOOTLOADER  = 120;
    const PCCOMM_GOTOREBOOT             = 130;
    
implementation

{$R *.dfm}

{******************************************************************************}
{ Thread }
{******************************************************************************}
procedure TNewThread.Execute;
var
    i: integer;
begin                    
    logtext := 'Поток создан, id:'+inttostr(self.ThreadID);
    Synchronize(AddToLog);    

    while not Terminated do 
    begin 
    //    В этом месте выполняется весь необходимый код.

    //Synchronize(MyUpdateProcedure);
    Sleep(10);
    end;
    
    logtext := 'Поток уничтожен, id:'+inttostr(self.ThreadID);
    Synchronize(AddToLog);
end;

procedure TNewThread.AddToLog();
begin
    Form1.Memo_Log.lines.Add(logtext);
end;
{******************************************************************************}
{ Thread }
{******************************************************************************}

{******************************************************************************}
{ MainProgramm }
{******************************************************************************}
{procedure TForm1.Button1Click(Sender: TObject);
var
    I: Integer;
  Data: Treport;
  Written: Cardinal;
  ToWrite: Cardinal;
  str:string[255];
begin
    if Assigned(Device) then
  begin
        str:='';
    ToWrite := Device.Caps.OutputReportByteLength;
        Data.ReportID:=0;
    for I := 1 to ToWrite-1 do Data.Data[I] := 0;
    Data.Data[0] := PCCOMM_SET;
    Data.Data[13] := 5;
    Device.WriteFile(Data, ToWrite, Written);
  end;
end; }

procedure TForm1.Button2Click(Sender: TObject);
begin
    //Memo_Log.Lines.Add('Device "'+ Device.ProductName + '" Connected!');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
    //Начальная инициализация программы

    cncdev := TCNCDevice.Create;   //Создание объекта TCNCDevice

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
    //Уничтожение программы
    
  If devThread <> nil then
    begin
        devThread.Terminate;
        while devThread <> nil do ;
    end;
    FreeAndNil(cncdev);                         //Освобождение памяти
end;

procedure TForm1.Hid1Arrival(HidDev: TJvHidDevice);
begin
    Memo_Log.lines.Add('Событие: Hid1Arrival, устройство '+HidDev.ProductName);
    if(HidDev.ProductName = MyDeviceProductName) AND
        (HidDev.Attributes.VendorID = MyDeviceVendorID) AND
        (HidDev.Attributes.ProductID = MyDeviceProductID) then
    begin
        If not Assigned(cncdev.Device) then Hid1.Enumerate
    end;
end;

procedure TForm1.Hid1DeviceData(HidDev: TJvHidDevice; ReportID: Byte; const Data: Pointer; Size: Word);
var
    i,p: Integer;
    arr  : Array[0..63] of Byte;
begin
  for I := 0 to 63 do
  begin
    if((i+1) mod 2 = 0)then
    begin
      arr[i]:=Cardinal(PChar(Data)[Round((I+1)/2)-1]) shr 8;
            arr[i-1]:=Cardinal(PChar(Data)[Round((I+1)/2)-1]) AND $FF;
    end;
    end;

end;

procedure TForm1.Hid1DeviceDataError(HidDev: TJvHidDevice; Error: Cardinal);
begin
    //Memo_Log.Lines.Add('READ ERROR: ' + SysErrorMessage(Error));
    cncdev.lasterror := Error;
end;

function TForm1.Hid1Enumerate(HidDev: TJvHidDevice; const Idx: Integer): Boolean;
begin             
    Memo_Log.lines.Add('Событие: Hid1Enumerate, устройство '+HidDev.ProductName+', idx '+inttostr(idx));
    Result:= True;                      // продолжать поиск
    if(HidDev.ProductName = MyDeviceProductName) AND
        (HidDev.Attributes.VendorID = MyDeviceVendorID) AND
        (HidDev.Attributes.ProductID = MyDeviceProductID) then
    begin
        Memo_Log.Lines.Add('Устройство найдено, создание потока');
        Hid1.CheckOutByIndex(cncdev.device, Idx);  // получаем устройство по индексу
        cncdev.device := HidDev;
        cncdev.online := true;
        
        devThread:=TNewThread.Create(true);
        devThread.FreeOnTerminate:=true;
        devThread.Priority:=tpHighest;
        devThread.Resume;    
        Result:= False;   // поиск закончен
    end;

end;

procedure TForm1.Hid1Removal(HidDev: TJvHidDevice);
begin
    Memo_Log.lines.Add('Событие: Hid1Removal, устройство '+HidDev.ProductName);
    if(HidDev.ProductName = MyDeviceProductName) AND
        (HidDev.Attributes.VendorID = MyDeviceVendorID) AND
        (HidDev.Attributes.ProductID = MyDeviceProductID) then
    begin
        If devThread <> nil then
        begin
            if not devThread.Terminated then
            begin
            Memo_Log.Lines.Add('Вызываю метод "devThread.Terminate"');
            devThread.Terminate;
            Memo_Log.Lines.Add('Метод вызван успешно');
      end;
        end;

            cncdev.device := nil; 
            cncdev.online := false;
  end;
end;

procedure TForm1.N2Click(Sender: TObject);
begin
 exit;   
end;

end.


Это сообщение отредактировал(а) Specialistvlad - 20.10.2010, 13:36
PM MAIL   Вверх
ZBugz
Дата 20.10.2010, 15:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 636
Регистрация: 15.2.2006
Где: Москва

Репутация: 6
Всего: 6



А где код остановки потока ?
PM MAIL   Вверх
Specialistvlad
Дата 20.10.2010, 15:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 20.10.2010

Репутация: нет
Всего: нет



Вот в этой процедуре
Код

procedure TForm1.Hid1Removal(HidDev: TJvHidDevice);
begin
    Memo_Log.lines.Add('Событие: Hid1Removal, устройство '+HidDev.ProductName);
    if(HidDev.ProductName = MyDeviceProductName) AND
        (HidDev.Attributes.VendorID = MyDeviceVendorID) AND
        (HidDev.Attributes.ProductID = MyDeviceProductID) then
    begin
        If devThread <> nil then
        begin
            if not devThread.Terminated then
            begin
            Memo_Log.Lines.Add('Вызываю метод "devThread.Terminate"');
            devThread.Terminate;
            Memo_Log.Lines.Add('Метод вызван успешно');
      end;
        end;

            cncdev.device := nil; 
            cncdev.online := false;
  end;
end;

PM MAIL   Вверх
RomanEEP
Дата 20.10.2010, 18:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 424
Регистрация: 18.5.2006
Где: Коломна

Репутация: 5
Всего: 8



1) Если процессор загружен программой, значит что-то выполняется. Попробуй воткнуть точки останова на возможные места, например TNewhread.Execute. Возможно программа начинает крутиться где-нибудь в цикле процедуры, которая вызывает TNewhread.Execute.
2)Еще лучше будет сперва также посмотреть какой процесс занимает процесорное время.
Может помочь также установка программы на паузу в Delphi
3)Надо обнулять указатель devThread при его уничтожении потока. Т.к. этого нет, то программа гарантировано зависнет на закрытии
4)Потоков может быть много - любая виндовая функция может создавать потоки, в используемых DLL, в компонентах.. в общем где угодно. Потоку можно присвоить имя для удобства отладки
5)не стоит назначать приоритет tphighest. Производительности это не прибавит, зато повесит остальные приложения и интерфейс.
PM MAIL   Вверх
Specialistvlad
Дата 20.10.2010, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 20.10.2010

Репутация: нет
Всего: нет



1.
Цитата

Возможно программа начинает крутиться где-нибудь в цикле процедуры, которая вызывает TNewhread.Execute


Ты лог смотрел? Или пропустил его ? Там явно видно, что с TNewhread.Execute выходит т.к. выполняются строки
Код

logtext := 'Поток уничтожен, id:'+inttostr(self.ThreadID);
    Synchronize(AddToLog); 

и с этого потока программа выходит. Другой мною поток не был создан. Или создан но я не знаю об этом.(Добавлено: программа в процедуру TNewhread.Execute не заходит после того как я завершаю поток (devThread.Terminate;), проверил с помощью точек останова)

2. 
Цитата

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

3. 
Цитата

Надо обнулять указатель devThread при его уничтожении потока. Т.к. этого нет, то программа гарантировано зависнет на закрытии

А разве при создании потока не хватает для этого такой строчки?  
Код

devThread.FreeOnTerminate:=true;


4. 
Цитата

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

А это тут причем? Речь идет только о моем проекте, а не о других программах.

5. 
Цитата

не стоит назначать приоритет tphighest. Производительности это не прибавит, зато повесит остальные приложения и интерфейс.

Возьму на заметку, но когда я лоувер приоритет ставлю, то остановка потока продолжается где-то 1.5секунды, а с этим приоритетом - моментально.
PM MAIL   Вверх
ZBugz
Дата 20.10.2010, 19:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 636
Регистрация: 15.2.2006
Где: Москва

Репутация: 6
Всего: 6



Я ничего по коду понять не могу smile

devThread.Terminated обычно не работает, у меня точно smile 
Далее,
Код

devThread.Terminate;
Memo_Log.Lines.Add('Метод вызван успешно');

не корректно, потому что Terminate не гарантирует остановку потока. Это тока комманда на остановку потока. Поэтому вывод в memo смысла не имеет. Его надо заменить на Memo_Log.Lines.Add('Метод терминат ушел');
Тут лучше свой деструктор делать.
Так же не пойму код, я конечно понимаю что он урезан, но возможно проблема с выводом инфы, в execute убери любое vcl обращение да и проверь как будет.

Добавлено через 2 минуты и 12 секунд
Код

devThread.FreeOnTerminate:=true;

Не гарантирует остановку потока. Остановку потока гарантирует только свой деструктор.

Добавлено через 3 минуты и 14 секунд
И тебе сказали првильно:
Цитата

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

Не важно что это твоя программа, тут как винда решит, тормозить его или нет.

Это сообщение отредактировал(а) ZBugz - 20.10.2010, 19:28
PM MAIL   Вверх
Specialistvlad
Дата 20.10.2010, 20:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 20.10.2010

Репутация: нет
Всего: нет



Цитата

Цитата

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


Не важно что это твоя программа, тут как винда решит, тормозить его или нет.


Теперь я понял о чем вы. В данном случае, скорее всего, третий поток принадлежит компоненту "JvHIDController". Который начинает работать с моим USB устройством.

Цитата

Так же не пойму код, я конечно понимаю что он урезан, но возможно проблема с выводом инфы, в execute убери любое vcl обращение да и проверь как будет.

Никаких изменений.

Цитата

Так же не пойму код, я конечно понимаю что он урезан, но возможно проблема с выводом инфы, в execute убери любое vcl обращение да и проверь как будет.

Суть проста.
В процедуре
procedure TForm1.Hid1Enumarate(HidDev: TJvHidDevice); - создавать поток,
а в 
procedure TForm1.Hid1Removal(HidDev: TJvHidDevice); - уничтожать поток.

Подскажите пожалуйста, правильный, рабочий деструктор. Потому что из всех статей, что я видел там был такой способ реализован как у меня. То есть 
Создается поток и начинает выполнятся процедура TNewhread.Execute, внутри которой цикл со слипом, из него выход возможен, только когда свойство devThread.Terminated; будет true. А true можно установить с помощью devThread.Terminate;
PM MAIL   Вверх
ZBugz
Дата 20.10.2010, 20:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 636
Регистрация: 15.2.2006
Где: Москва

Репутация: 6
Всего: 6



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

Код

unit ThreadUnit;

interface

uses
  Windows, и т.д. что там тебе надо...
const
  WM_THREAD_COMPLETE = WM_APP + 123; тут любое число, это уникальное число для твоей формы

type
  TZThread = class(TThread)
    Prior1: TThreadPriority;
  private
    procedure Complete;
    procedure Error;
    procedure MyThreadTerminate(Sender: TObject);
  protected
    procedure Execute; override;
    procedure Progress;
  public
    constructor Create (Prior: TThreadPriority и другие переменные которые тебе нужны);
    procedure MyError(E : Exception );
    destructor Destroy; override;
  end;
implementation

uses MainUnit;


procedure TZThread.MyThreadTerminate(Sender: TObject);
begin
 // тут типа завершаеться
end;

destructor TZThread.Destroy;
begin
  inherited Destroy;
end;
constructor TZThread.Create(Prior: TThreadPriority);
begin
  inherited Create (True);
  Priority := Prior1;
  OnTerminate := MyThreadTerminate;
  FreeOnTerminate := False;
end;

procedure TZThread.Error;
Begin
// тут ошибки выводишь
End;

Procedure TZThread.MyError(E:Exception);
begin
 S:=SysErrorMessage(GetLastError);
 Synchronize(Error);
end;

procedure TZThread.Complete;
begin
// типа усе сделал
end;

procedure TZThread.Progress;
begin
// тут сам процесс можно высвести на экран
end;

procedure TZThread.Execute;
begin
 try
 try
   чето делаем и тогда  Synchronize(Progress);
   чето сделали и тогда  Synchronize(Complete);
      end;
     except
    MyError(Exception(ExceptObject));
   end
  finally
   PostMessage(MainForm.Handle, WM_THREAD_COMPLETE, 0, 0); // я обычно где 0 использую как результат завершения, ну типа 0, 0 все хорошо, 0,1 ошибка, 0,2 вообще пипец и т.д.
   application.ProcessMessages;
  end;
 end;
end.

А в форме добавляешь uses unit треда
потом это:
Код

  private
    CT: array [1..2000] of TCopyThread;
    procedure ThreadComplete(var Message: TMessage); message WM_THREAD_COMPLETE;

Потом в кнопке запуска пишешь:
CT[idx] := TCopyThread.Create(Prior);
 CT[idx].Start;
Где idx номер задания или что там у тебя...



Кнопка стоп
Код

CT[idx].Terminate;


А вот и сама процедура завершения, тут уже 100% поток завершен и можешь делать что хочешь.
Код

procedure TMainForm.ThreadComplete(var Message: TMessage);
begin
   if Assigned(CT[Message.WParam]) then
    begin
      CT[Message.WParam].WaitFor;
      FreeAndNil(CT[Message.WParam]);
    end;


Уж извиняй, в блокноте писал smile Если что не понятно, могу завтра сделать нормальный пример.
PM MAIL   Вверх
RomanEEP
Дата 20.10.2010, 22:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 424
Регистрация: 18.5.2006
Где: Коломна

Репутация: 5
Всего: 8



Цитата(Specialistvlad @  20.10.2010,  18:36 Найти цитируемый пост)
 Речь идет только о процессе моей программы, в данном случае Project1, он грузит проц.

Описался, имел ввиду узнать какой поток занимает процессорное время и попытаться его остановить отладчиком в Delphi 

Цитата(Specialistvlad @  20.10.2010,  18:36 Найти цитируемый пост)
А разве при создании потока не хватает для этого такой строчки?  код Pascal/Delphi1:devThread.FreeOnTerminate:=true;

Нет, конечно. Эта строчка уничтожает объект потока после того как он отработал. Как известно, на этот объект может быть множество указателей, о которых может знать только программист, который их объявлял. В твоем случае есть только один указаль - devThread  и его следует обнулять, например, в деструкторе потока.

PM MAIL   Вверх
Specialistvlad
Дата 21.10.2010, 11:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 20.10.2010

Репутация: нет
Всего: нет



ZBugz, спасибо за такой подробный код и описание. Пришлось подпилить напильником, много незначительных ошибок, из-за блокнота=) но это не суть, вот что получилось у меня.
Код

unit Unit2;

interface

uses
    Windows, Messages, Forms, Classes, SysUtils;
const
    WM_THREAD_COMPLETE = WM_APP + 123;// тут любое число, это уникальное число для твоей формы

type
    TMyThread = class(TThread)  
    private
    err:string;
    procedure Complete;
    procedure Error;
        procedure MyThreadTerminate(Sender: TObject);
  protected
    procedure Execute; override;
        procedure Progress;
    public
        constructor Create(Prior: TThreadPriority);        // и другие переменные которые тебе нужны
        destructor Destroy; override;
        procedure MyError(E : Exception);
    end;

implementation

uses Unit1;           //Юнит основного приложения

{ TMyThread }

procedure TMyThread.MyThreadTerminate(Sender: TObject);
begin
 // тут типа завершается
end;

destructor TMyThread.Destroy;
begin
  inherited Destroy;
end;

constructor TMyThread.Create(Prior: TThreadPriority);
begin
    inherited Create(True);
    Priority := Prior;
  OnTerminate := MyThreadTerminate;
  FreeOnTerminate := False;
end;

procedure TMyThread.Error;
Begin
// тут ошибки выводишь из err
End;

Procedure TMyThread.MyError(E:Exception);
begin
 err:=SysErrorMessage(GetLastError);
 Synchronize(Error);
end;

procedure TMyThread.Complete;
begin
// типа усе сделал
end;

procedure TMyThread.Progress;
begin
// тут сам процесс можно высвести на экран
end;

procedure TMyThread.Execute;
begin
    try
        try
                 {чето делаем и тогда  Synchronize(Progress);
                 чето сделали и тогда  Synchronize(Complete);}
        except
    MyError(Exception(ExceptObject));
        end
  finally
     PostMessage(Form1.Handle, WM_THREAD_COMPLETE, 0, 0); // я обычно где 0 использую как результат завершения, ну типа 0, 0 все хорошо, 0,1 ошибка, 0,2 вообще пипец и т.д.
     Application.ProcessMessages;
  end;
 end;
end.



Вылетает на этой строке в эксепшон, не пойму, эт что конструктор сам себя запускает?) Я в 

Цитата

constructor TMyThread.Create(Prior: TThreadPriority);
begin
    inherited Create(True);
    Priority := Prior;
    OnTerminate := MyThreadTerminate;
    FreeOnTerminate := False;
end;

P.S. Я пишу на Си для микроконтроллеров и к прикладному программированию мало отношения имею. А вспомнил, что когда-то под делфи пробовал писать под виндоуЗ, то взялся за него.. 

Это сообщение отредактировал(а) Specialistvlad - 21.10.2010, 11:34
PM MAIL   Вверх
Specialistvlad
Дата 21.10.2010, 13:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 20.10.2010

Репутация: нет
Всего: нет



Не пойму как это работает.

Код

inherited Create(True);

Цитата

Ключевое слово Inherited используется, чтобы назвать родительский конструктор или метод деструктора, как соответствующий для текущего класса.

PM MAIL   Вверх
ZBugz
  Дата 21.10.2010, 15:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 636
Регистрация: 15.2.2006
Где: Москва

Репутация: 6
Всего: 6



Короче, вот пример smile 

Присоединённый файл ( Кол-во скачиваний: 20 )
Присоединённый файл  Thread.rar 3,22 Kb
PM MAIL   Вверх
Specialistvlad
Дата 21.10.2010, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 20.10.2010

Репутация: нет
Всего: нет



Мего спасибо! Завелось и работает!))
PM MAIL   Вверх
ZBugz
Дата 21.10.2010, 16:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 636
Регистрация: 15.2.2006
Где: Москва

Репутация: 6
Всего: 6



Пожайлуста, как на СИ переведешь, можешь выложить пример в нужном разделе, может кому пригодиться.

И не забудь что 
Код

PostMessage(Form1.Handle, WM_THREAD_COMPLETE, НОМЕР ПОТОКА ЭТО ДЛЯ ОСТАНОВКИ, 0);

А 0 можно как любые события потом обрабатывать, это l.param 
PM MAIL   Вверх
Specialistvlad
Дата 21.10.2010, 17:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 20.10.2010

Репутация: нет
Всего: нет



Ты не понял, я на си пишу ответную программу под микроконтроллер, а в делфях прикладнуху. Вот так. =)
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1007 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.