Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 22.09.2012, 21:47   #1
crossmark
Пользователь
 
Регистрация: 13.03.2010
Сообщений: 27
По умолчанию Эти странные потоки

Доброго времени!
Поставил цель побороться с WinSock. Но столкнулся с проблемой с потоками. Не получается в поток передать параметры. Подскажите что не так. Может из-за того что класс и память получается разная?
Это лишь кусочек кода.
Код:
unit socket_u;

interface

uses windows,winsock,messages;

type TParamThread=record
      hServSocket:integer;
end;
PParamThread=^TParamThread;


type TServerSock=class
private
  wsData : WSADATA;
  SocketAdrr : sockaddr_in;
  ServType : TServType;
  function CreateSocket:integer; //шаг 2 создание сокета
  function SetServSocket:integer; // шаг 3  настройка сокета
  function SyncServ:integer;
  function SockConnect: integer; //соединение
  function SockAccept(accept_cocket:TSocket; addr: PSOCKADDR; addrlen: PInteger ): TSocket;
public
  ServSocket : integer;
  errCreate : boolean;
  constructor create;    //шаг 1 инициализация сокета
  destructor destroy;
  function ServerConnect:boolean;
  function GetNameHost:String;
  function GetIPAdress(name:PAnsiChar):string;
  procedure NetMsg(var M:TMessage); message WM_MESS;
  function ServerRecv(accept_cocket:TSocket; buf:PAnsiChar;len,flags:integer):integer; // recv получение данных
  function ServerSend(accept_cocket:TSocket; buf:PAnsiChar;len,flags:integer):integer; // send отправка данных
  procedure ServerCreateThread;
  function SockWait(s:pointer):DWORD;
end;


var vServType:TServType;
    vClientType:TClientType;
    Param:PParamThread;
implementation


procedure TServerSock.ServerCreateThread;
var //thread:array[1..100] of cardinal;
    hThread:THandle;
    ThreadID:DWORD;
    p:pointer;
begin
    hThread:=BeginThread(nil, 0, Addr(TServerSock.SockWait), param, 0, threadID);

end;

function TServerSock.SockWait(s:pointer):DWORD;
var csocket:TSocket;
    cs:integer;
    buf:array[1..100]of pansichar;
    i:integer;
    p:TParamThread;
begin
   p:=PParamThread(s)^;
   Finalize(PParamThread(S)^);
 //   FreeMem(S);
  while True do
  begin
      sleep(1);
      //csocket:=SockAccept(ServSocket,Pointer(@SocketAdrr),Pointer(@SocketAdrr));
      i:=sizeof(SocketAdrr);
      csocket:=accept(Result,Pointer(@SocketAdrr),pointer(i));
      if csocket<>-1 then
      begin
       serverrecv(csocket,buf[1],sizeof(buf),0);
       messagebox(0,PWideChar(buf[1]),PCHAR('Recv'),mb_ok);
      end;
      if csocket<> INVALID_SOCKET then
         begin
             closesocket(csocket); // закрываем сокет
         end;
  end;
end;
Т.е. hThread:=BeginThread(nil, 0, Addr(TServerSock.SockWait), param, 0, threadID); Тут param получает значение номер сокета, а в функции function TServerSock.SockWait(sointer):DWO RD;
s получается пустой. точнее какой то мусор наверное. тут p:=PParamThread(s)^; очень большое значение.
Что не так, уже сутки думаю....
Спасибо
crossmark вне форума Ответить с цитированием
Старый 23.09.2012, 00:11   #2
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

прототип входа в поток описан так:

Код:
TThreadFunc = function(Parameter: Pointer): Integer;
и "Addr(TServerSock.SockWait)" не прокатит, т.к. метод TServerSock.SockWait() ожидает первым неявым параметром self, а потом уже s. Естественно, никакого self ему не передается, а в s попадает мусор.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."

Последний раз редактировалось veniside; 23.09.2012 в 00:19.
veniside вне форума Ответить с цитированием
Старый 23.09.2012, 11:49   #3
crossmark
Пользователь
 
Регистрация: 13.03.2010
Сообщений: 27
По умолчанию

процедуру вынес за пределы класса и все успешно передается... а почему тогда в классе приходит мусор? и что нет решения?
crossmark вне форума Ответить с цитированием
Старый 23.09.2012, 12:37   #4
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

> а почему тогда в классе приходит мусор?

Цитата:
ожидает первым неявым параметром self, а потом уже s. Естественно, никакого self ему не передается, а в s попадает мусор.
> и что нет решения?

Цитата:
процедуру вынес за пределы класса и все успешно передается
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 23.09.2012, 16:54   #5
crossmark
Пользователь
 
Регистрация: 13.03.2010
Сообщений: 27
По умолчанию

спасибо!
и все же появился вопрос... ПОЧЕМУ ТАК передается... где можно подробно это прочитать... ? уж больно интересно
crossmark вне форума Ответить с цитированием
Старый 23.09.2012, 19:20   #6
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

почему self ожидается первым параметром? ну, так устроены все методы классов. Можно считать, что любой метод класса (кроме конструктора), объявлен примерно так:

Код:
type
  myClass = class
    procedure some(self: myClass; ...остальные параметры, если есть...)
  end;
Виндовс, естественно об этом ничего не знает, и считает, что процедура входа в поток ожидает ровно один параметр: тот, значение которого задается в CreateThread(). Этим можно воспользоваться, чтобы вернуться в метод класса:

Код:
type
  myThreadClass = class
    procedure onThreadStart(); // выполняется в новом потоке    
  end;

// --  --
function threadEntry(param: myThreadClass): DWORD; stdcall;
begin
  param.onThreadStart();
  //
  result := 0;
end;

  ....
  // создаем и запускаем новый поток
  thread := myThreadClass.create();
  CreateThread(nil, 0, @threadEntry, thread, 0, id);
почему так не сделали в BeginThread(), не знаю, видимо, посчитали, что класса TThread будет достаточно.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 23.09.2012, 19:52   #7
xoodoo
Форумчанин
 
Регистрация: 11.04.2012
Сообщений: 212
По умолчанию

Цитата:
почему так не сделали в BeginThread(), не знаю
А чего там "не сделали" ?
Прототип BeginThread() за исключением соглашения о вызове один-в-один совпадает с CreateThread, так что ничто не мешает и в BeginThread() передать параметром свой объект, так же как в CreateThread ..
Ну и получить при вызове BeginThread() еще и "бонусы" : как минимум сэкономить на реализации собственной предобработки исключений и автоматически известить встроенный дельфийский менеджер памяти о потенциальных мультипоточных к нему обращениях.

Цитата:
посчитали, что класса TThread будет достаточно
Скорее так - посчитали что BeginThread будет недостаточно и представили дополнительно "более удобный" интерфейс для организации многопоточности в VCL-приложении.

Последний раз редактировалось xoodoo; 23.09.2012 в 19:55.
xoodoo вне форума Ответить с цитированием
Старый 23.09.2012, 20:02   #8
crossmark
Пользователь
 
Регистрация: 13.03.2010
Сообщений: 27
По умолчанию

Цитата:
Сообщение от veniside Посмотреть сообщение
почему self ожидается первым параметром? ну, так устроены все методы классов. Можно считать, что любой метод класса (кроме конструктора), объявлен примерно так:

Код:
type
  myClass = class
    procedure some(self: myClass; ...остальные параметры, если есть...)
  end;
Виндовс, естественно об этом ничего не знает, и считает, что процедура входа в поток ожидает ровно один параметр: тот, значение которого задается в CreateThread(). Этим можно воспользоваться, чтобы вернуться в метод класса:

Код:
type
  myThreadClass = class
    procedure onThreadStart(); // выполняется в новом потоке    
  end;

// --  --
function threadEntry(param: myThreadClass): DWORD; stdcall;
begin
  param.onThreadStart();
  //
  result := 0;
end;

  ....
  // создаем и запускаем новый поток
  thread := myThreadClass.create();
  CreateThread(nil, 0, @threadEntry, thread, 0, id);
почему так не сделали в BeginThread(), не знаю, видимо, посчитали, что класса TThread будет достаточно.
обалдеть.... я даже и не думал что так можно. кинуть весь класс в параметры. я такого и не видел ни где.
спасибо! я обязательно это запомню. и при первой же возможности применю.
огромное спасибо!
crossmark вне форума Ответить с цитированием
Старый 23.09.2012, 20:03   #9
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

> А чего там "не сделали" ?

ну могли бы TObject расширить ещё одним виртуальным методом, который бы вызывался из BeginThread(). Было бы красиво.


> не думал что так можно. кинуть весь класс в параметры

экземпляр класса -- это указатель, и параметр в CreateThread() тоже имеет размер указателя, так что проблем не возникает.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."

Последний раз редактировалось veniside; 23.09.2012 в 20:08.
veniside вне форума Ответить с цитированием
Старый 23.09.2012, 20:18   #10
crossmark
Пользователь
 
Регистрация: 13.03.2010
Сообщений: 27
По умолчанию

не сделал потому что... потому что сервер не хочет видеть клиента. хотя через TCPView вроде они подключаются.
вот когда они увидят друг друга, вот тогда попробую все это применить
crossmark вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Странные таблицы Port Microsoft Office Word 4 18.05.2011 12:01
странные проблемы с с++ Plastilin Общие вопросы C/C++ 9 21.02.2010 03:50
Странные ошибки. Rio309 Общие вопросы Delphi 2 19.10.2009 19:22
Странные задачи L_M Свободное общение 60 19.05.2009 08:54