Problem z wątkami

0

Tym razem nie chodzi o niedziałający kod. Mój kod działa, nawet nieźle. Więc w czym problem? Zacznijmy od początku.

Jak pewnie (nie) wiecie piszę EasyScript który jest interpreterem mojego języka ES. Działa on bez zarzutu, nawet coś czasami go rozwijam, ale chodzi tutaj o podstawę jego działania, a mianowicie o sposób wykonywania procedury jak IF,SET,ADD czy cokolwiek.
Mianowicie, mam ustalony wzór procedury która może być wykonywana przez ES, gdzieś mam też do niej wskaźnik. Wszystko śmiga.

Stosuje ES międzyinnymi w jednym z moich większych projektów PRNDWN. Jest to bot internetowy, który skacze po stronach i pobiera jakieśtam pliki - definicję jak ma to zrobić są właśnie w ES. PRNDWN jest wielowątkowy. I tu zaczynają się schody, bo:
Mam pare interpreterów ES (w obiektach). Jeden na główny wątek i po jednym na każdy wątek poszukiwacza. Problem polega na tym, że większość dodanych (na potrzeby PRNDWN) procedur ES musi się odwołać do obiektu wątku, którego nie osiągniemy od tak. Dlatego zrobiłem zmienną globalną, i gdy któryś wątek wykonuje ES to przypisuje pod tą zmienną referencję do siebie.

I tu jest problem:
Jest szansa, że gdy jeden wątek będzie wykonywać polecenia, drugi wątek zmieni referencję, i stanie się coś nieciekawego. Albo (tutaj akurat nie jestem pewien) dwa interpretery ES wykonają naraz tą samą procedurę - też problem.

Myślałem już nad zrobiniem sekcji krytycznej, ale spowodowałoby to zdecydowanie zmniejszenie wydajności ES i co za tym idzie całego programu.
Macie może jakieś pomysły jak to rozwiązać?
Jeszcze taka mała podpowiedź: ES jest teoretycznie obiektowy a w praktyce to spora część jego kodu niskiego poziomu jest w procedurach.

0

napisać porządnie aby się nie gryzły wątki między sobą i każdy miał swoją kopię danych na których będzie operował

0
Misiekd napisał(a)

napisać porządnie aby się nie gryzły wątki między sobą i każdy miał swoją kopię danych na których będzie operował

A jak mam coś takiego zrobić z procedurami?
Jeśli procedura będzie w obiekcie to procedura w innym obiekcie będzie 'inna'? Bo nad tym głównie rozmyślałem.
Dane już w 99% przypadków są threadsafe (sekcje krytyczne)/skopiowane dla wątków.

0
payl napisał(a)

Jeśli procedura będzie w obiekcie to procedura w innym obiekcie będzie 'inna'? Bo nad tym głównie rozmyślałem.

a po polsku

0
Misiekd napisał(a)

a po polsku

Tak myślałem że nie skumasz.

Tłumacząc działanie ES jeszcze raz:
Mam sobię tablicę z nazwą procedury, typami które przyjmuje oraz wskaźnik na realną procedurę, którą potem wykonuję. Jak według Ciebie miałoby to wyglądać w wersji obiektowej?

Tutaj masz kod:

type
GoProc=Function(pESint:pointer;var_ls:TES_Pvrlst;org_s:tes_string):integer stdcall;

TES_Proc=record
		naz:string;
		addr:pointer;//Wskaźnik na procedurę
		lvr:TES_Lvrlst;
		accept_any_vars:boolean;
		wer:word;
		end;

[...]
function ES_SYS_VER_MAJ(pESint:pointer;var_ls:TES_Pvrlst;org_s:tes_string):integer stdcall;
begin
  [...]
end;

[...]
	proc.naz:='VER_MAJ';
	setlength(proc.lvr,1);
	proc.lvr[0].typ:=es_nmb;
	proc.addr:=@ES_SYS_VER_MAJ;
	proc.accept_any_vars:=FALSE;
	addproc(proc);
[...]

Wykonanie:

go_procedure:=goproc(go_lst[PolID].addr);
result:=go_procedure(@tes_int(self),pvr,s);
res.typ:=es_anything;

I jak to zrobić obiektowo :P.

0

ale po co mi ten kod? Co sobie mam z nim zrobić? Jak od początku masz pisany kod nieobiektowo i nie thread-safe to teraz dwoma machnięciami się tego nie zmieni. Przypuszczam, że masz różne procedury z takimi samymi parametrami ale robiące różne rzeczy. Takie cudo to się przez dziedziczenie bardzo ładnie i prosto załatwia

0
Misiekd napisał(a)

Takie cudo to się przez dziedziczenie bardzo ładnie i prosto załatwia

Może jakiś przykład albo jaśniej? :P Bo póki co nie wiem jak miałoby to wyglądać.

0
type
  TZwierz = class
  public 
    function DajGlos: string; virtual; abstract;
  end;

  TKot = class(TZwierz)
  public 
    function DajGlos: string; override;
  end;

  TPies = class(TZwierz)
  public 
    function DajGlos: string; override;
  end;

implementation

function TKot.DajGlos: string; 
begin
  Result := 'miau';
end;

function TPies.DajGlos: string; 
begin
  Result := 'hau';
end;

//i gdzieś tam daleko
var
  zwierza: array [0..1] of TZwierz;
  i: Integer;
begin
  zwierza[0] := TKot.Create;
  zwierza[1] := TPies.Create;
  for i := 0 to 1 do
    WriteLn(zwierza[i].DajGlos);

  for i := 0 to 1 do
    zwierza[i].Free;
end;

i na takiej zasadzie w go_lst miał byś po prostu obiekty różnych typów ale dziedziczące po tym samym przodku

0
Misiekd napisał(a)

i na takiej zasadzie w go_lst miał byś po prostu obiekty różnych typów ale dziedziczące po tym samym przodku

Ooo genialne. Dzięki, misiekd :P

1 użytkowników online, w tym zalogowanych: 0, gości: 1