Thread Problematik / mehrere Parallel

Anfängerfragen zum Programmieren mit PureBasic.
smateja
Beiträge: 250
Registriert: 25.11.2004 19:51
Computerausstattung: Alienware Aurora / Intel Core i7 CPU @ 2.8 GHz / 64 Bit OS

Thread Problematik / mehrere Parallel

Beitrag von smateja »

Hallo zusammen,

ich bastel derzeit an einer kleinen Überwachung von Prozess-Zeiten herum. sprich die CPU Auslastung des einzelnen Prozesses. Das klappt mittlerweile auch schon ganz gut. Jetzt möchte ich aber mehrere Prozesse zur gleichen Zeit hin überprüfen - allerdings befürchte ich, dass hier dann die Threads auf die Gleichen Ressourcen zurückgreifen und dann crasht es. Evtl. hat hier ja jemand eine Idee was ich falsch mache - oder kann mir sagen was ich ändern muss, damit es funktioniert.

Achtung: Die entsprechenden Benamungen bei den EXE Files müsst ihr natürlich abändern, da es die EXE Dateien so wohl nicht bei euch gibt. (z.B. "rwfw_pcgi.exe" umbenennen in explorer.exe - oder welcher Task ihr halt zum testen heranziehen wollt)

Hier mal mein Code:

Code: Alles auswählen


Global Prozesszeit_WEB.d
Global Prozesszeit_PHP.d
Global Prozesszeit_SQL.d
Global Prozesszeit_FTP.d

Procedure Prozess_CPU_WEB(void) 
  creation.FILETIME 
  exit.FILETIME 
  kernel.FILETIME 
  user.FILETIME 
  
  sysinfo.SYSTEM_INFO 
  GetSystemInfo_(@sysinfo) 
  numprocs = sysinfo\dwNumberOfProcessors 
  
  h = OpenProcess_(#PROCESS_QUERY_INFORMATION, #False, GetPidProcess("rwfw_web.exe"))  
  GetProcessTimes_(h,@creation,@exit,@kernel,@user)
  oldkernel=kernel\dwlowdatetime
  olduser=user\dwlowdatetime
  Delay(500)
  
  Repeat
    GetProcessTimes_(h,@creation,@exit,@kernel,@user)
    Prozesszeit_WEB = ((((user\dwlowdatetime-olduser)+(kernel\dwlowdatetime-oldkernel))/500)/100)/numprocs
    olduser=user\dwlowdatetime
    oldkernel=kernel\dwlowdatetime    
    Delay (500)
  ForEver
  
EndProcedure
Procedure Prozess_CPU_PHP(void) 
  creation.FILETIME 
  exit.FILETIME 
  kernel.FILETIME 
  user.FILETIME 
  
  sysinfo.SYSTEM_INFO 
  GetSystemInfo_(@sysinfo) 
  numprocs = sysinfo\dwNumberOfProcessors 
  
  h = OpenProcess_(#PROCESS_QUERY_INFORMATION, #False, GetPidProcess("rwfw_pcgi.exe"))  
  GetProcessTimes_(h,@creation,@exit,@kernel,@user)
  oldkernel=kernel\dwlowdatetime
  olduser=user\dwlowdatetime
  Delay(500)
  
  Repeat
    GetProcessTimes_(h,@creation,@exit,@kernel,@user)
    Prozesszeit_PHP = ((((user\dwlowdatetime-olduser)+(kernel\dwlowdatetime-oldkernel))/500)/100)/numprocs
    olduser=user\dwlowdatetime
    oldkernel=kernel\dwlowdatetime    
    Delay (500)
  ForEver
  
EndProcedure
Procedure Prozess_CPU_SQL(void) 
  creation.FILETIME 
  exit.FILETIME 
  kernel.FILETIME 
  user.FILETIME 
  
  sysinfo.SYSTEM_INFO 
  GetSystemInfo_(@sysinfo) 
  numprocs = sysinfo\dwNumberOfProcessors 
  
  h = OpenProcess_(#PROCESS_QUERY_INFORMATION, #False, GetPidProcess("rwfw_sql.exe"))  
  GetProcessTimes_(h,@creation,@exit,@kernel,@user)
  oldkernel=kernel\dwlowdatetime
  olduser=user\dwlowdatetime
  Delay(500)
  
  Repeat
    GetProcessTimes_(h,@creation,@exit,@kernel,@user)
    Prozesszeit_SQL = ((((user\dwlowdatetime-olduser)+(kernel\dwlowdatetime-oldkernel))/500)/100)/numprocs
    olduser=user\dwlowdatetime
    oldkernel=kernel\dwlowdatetime    
    Delay (500)
  ForEver
  
EndProcedure 
Procedure Prozess_CPU_FTP(void) 
  creation.FILETIME 
  exit.FILETIME 
  kernel.FILETIME 
  user.FILETIME 
  
  sysinfo.SYSTEM_INFO 
  GetSystemInfo_(@sysinfo) 
  numprocs = sysinfo\dwNumberOfProcessors 
  
  h = OpenProcess_(#PROCESS_QUERY_INFORMATION, #False, GetPidProcess("rwfw_storage.exe"))  
  GetProcessTimes_(h,@creation,@exit,@kernel,@user)
  oldkernel=kernel\dwlowdatetime
  olduser=user\dwlowdatetime
  Delay(500)
  
  Repeat
    GetProcessTimes_(h,@creation,@exit,@kernel,@user)
    Prozesszeit_FTP = ((((user\dwlowdatetime-olduser)+(kernel\dwlowdatetime-oldkernel))/500)/100)/numprocs
    olduser=user\dwlowdatetime
    oldkernel=kernel\dwlowdatetime    
    Delay (500)
  ForEver
  
EndProcedure




Thread_WEB=CreateThread(@Prozess_CPU_WEB(),9000) 
Thread_PHP=CreateThread(@Prozess_CPU_PHP(),9001) 
Thread_SQL=CreateThread(@Prozess_CPU_SQL(),9002) 
Thread_FTP=CreateThread(@Prozess_CPU_FTP(),9003) 



Repeat 
  Debug StrD(Prozesszeit_WEB,2)
  Debug StrD(Prozesszeit_PHP,2)
  Debug StrD(Prozesszeit_SQL,2)
   Debug StrD(Prozesszeit_FTP,2)
  Delay(100)
ForEver

PB 4.6 / 32 Bit / 64 Bit
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Thread Problematik / mehrere Parallel

Beitrag von STARGÅTE »

Da ich in einem Code kein eiziges mal LockMutex oder UnlockMutex sehe, gebe ich einfach mal den Hinweis:
Benutze Mutex
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Thread Problematik / mehrere Parallel

Beitrag von NicTheQuick »

Ich sehe vier Prozeduren, die alle gleich aussehen. Wieso nimmst du nicht eine und parametrisierst sie mit dem zu überprüfenden Prozessname?

Ansonsten braucht man einen Mutex nur dann, wenn die entsprechenden API-Funktionen selbst nicht für Multithreading gedacht sind.
GetSystemInfo_() wird keine Probleme machen. Diese liest nur Daten.
OpenProcess_() wird auch kein Problem machen, GetProcessTimes_() sowieso nicht.

Wo crasht es denn genau? Sagt der Purifier etwas?
smateja
Beiträge: 250
Registriert: 25.11.2004 19:51
Computerausstattung: Alienware Aurora / Intel Core i7 CPU @ 2.8 GHz / 64 Bit OS

Re: Thread Problematik / mehrere Parallel

Beitrag von smateja »

Merci erstmal für die Rückmeldung - ich glaube zu wissen woran es liegt:

h = OpenProcess_(#PROCESS_QUERY_INFORMATION, #False, GetPidProcess("rwfw_storage.exe"))

die Funktion GetPidProcess von der Droopy Lib scheint hier das Problem zu machen - nicht aber wohl die Threads.

Mhmmm - kennt wer dann ne alternative zu:

Code: Alles auswählen


ProcedureDLL GetPidProcess(Name.s) ; Returns Pid of Process if it exists / 0 if it doesn't exist
  
  Name.s=UCase(Name.s)
  Recherche=0
  If OpenLibrary(0, "Kernel32.dll") 
    
    CreateToolhelpSnapshot = GetFunction(0, "CreateToolhelp32Snapshot") 
    ProcessFirst           = GetFunction(0, "Process32First") 
    ProcessNext            = GetFunction(0, "Process32Next") 
    
    If CreateToolhelpSnapshot And ProcessFirst And ProcessNext ; Ensure than all the functions are found 
      
      Process.PROCESSENTRY33\dwSize = SizeOf(PROCESSENTRY33) 
      
      Snapshot = CallFunctionFast(CreateToolhelpSnapshot, #TH32CS_SNAPPROCESS, 0) 
      If Snapshot 
        
        ProcessFound = CallFunctionFast(ProcessFirst, Snapshot, Process) 
        While ProcessFound 
          Nom.s=UCase(PeekS(@Process\szExeFile))
          Nom=GetFilePart(Nom)
          If Nom=Name 
            Recherche =1 
            Pid=Process\th32ProcessID
          EndIf
          ProcessFound = CallFunctionFast(ProcessNext, Snapshot, Process) 
        Wend 
      EndIf 
      
      CloseHandle_(Snapshot) 
    EndIf 
    
    CloseLibrary(0) 
  EndIf 
  
  ProcedureReturn Pid
EndProcedure 




Hab auch schon in der WinApi mal geschaut - allerdings bekomme ich hier nur:

Code: Alles auswählen

EnableExplicit

Define PID

GetWindowThreadProcessId_(FindWindow_("notepad",#Null),@PID)
MessageRequester("","PID: "+Str(PID),0)
Das dumme daran ist, das ich ja kein Fensternamen habe - hilfe *G - ich klemm komplett jetzt glaub.
PB 4.6 / 32 Bit / 64 Bit
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Thread Problematik / mehrere Parallel

Beitrag von ts-soft »

Habe Dir die GetPidProcess Procedure mal umgeschrieben, so wie es für PB4 und grösser IMHO sein sollte :mrgreen:

Code: Alles auswählen

Procedure GetPidProcess(Name.s)
  Protected Snapshot, ProcessFound, Nom.s
  Protected.PROCESSENTRY32 Process
  
  Process\dwSize = SizeOf(PROCESSENTRY32)
  
  If Name
    Name = UCase(Name)
    Snapshot = CreateToolhelp32Snapshot_(#TH32CS_SNAPPROCESS, 0)
    If Snapshot
      ProcessFound = Process32First_(Snapshot, Process)
      While ProcessFound
        Nom = UCase(PeekS(@Process\szExeFile[0]))
        If Nom
          Nom = GetFilePart(Nom)
          If Nom = Name
            ProcedureReturn Process\th32ProcessID
          EndIf
        EndIf
        ProcessFound = Process32Next_(Snapshot, Process)
      Wend
    EndIf
  EndIf
EndProcedure
Die procedure hält auch einem EnableExplicit stand, was ich Dir ans Herz legen würde.

Aber ob es beim eigentlichen Problem hilft, weiß ich jetzt nicht.

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Thread Problematik / mehrere Parallel

Beitrag von NicTheQuick »

Die Funktion GetPidProcess() brauchst du ja pro Thread nur einmal. Von daher wäre die einfachste Lösung, zunächst mittels GetPidProcess() alle ProzessIDs zu holen und diese dann den Threads zu übergeben. Ab dem Punkt sollte es dann ja klappen.
Also ungefähr so. Leider konnte ich das ganze nicht testen, da ich kein Windows habe.

Code: Alles auswählen

Structure Prozesszeit
	pid.i
	zeit.d
	thread.i
EndStructure

Global Prozesszeit_WEB.d
Global Prozesszeit_PHP.d
Global Prozesszeit_SQL.d
Global Prozesszeit_FTP.d

Procedure Prozess_CPU(*zeit.Prozesszeit)
	creation.FILETIME
	exit.FILETIME
	kernel.FILETIME
	user.FILETIME
	
	sysinfo.SYSTEM_INFO
	GetSystemInfo_(@sysinfo)
	numprocs = sysinfo\dwNumberOfProcessors
	
	h = OpenProcess_(#PROCESS_QUERY_INFORMATION, #False, *zeit\pid) 
	GetProcessTimes_(h,@creation,@exit,@kernel,@user)
	oldkernel=kernel\dwlowdatetime
	olduser=user\dwlowdatetime
	Delay(500)
	
	Repeat
		GetProcessTimes_(h,@creation,@exit,@kernel,@user)
		*zeit\zeit = ((((user\dwlowdatetime-olduser)+(kernel\dwlowdatetime-oldkernel))/500)/100)/numprocs
		olduser=user\dwlowdatetime
		oldkernel=kernel\dwlowdatetime   
		Delay (500)
	ForEver
	
EndProcedure

Define WEB.ProzessZeit, PHP.Prozesszeit, SQL.Prozesszeit, FTP.Prozesszeit

WEB\pid = GetPidProcess("rwfw_web.exe")
PHP\pid = GetPidProcess("rwfw_pcgi.exe")
SQL\pid = GetPidProcess("rwfw_sql.exe")
FTP\pid = GetPidProcess("rwfw_storage.exe")



WEB\thread = CreateThread(@Prozess_CPU(), @WEB)
PHP\thread = CreateThread(@Prozess_CPU(), @PHP)
SQL\thread = CreateThread(@Prozess_CPU(), @SQL)
FTP\thread = CreateThread(@Prozess_CPU(), @FTP)



Repeat
	Debug StrD(WEB\zeit, 2)
	Debug StrD(PHP\zeit, 2)
	Debug StrD(SQL\zeit, 2)
	Debug StrD(FTP\zeit, 2)
	Delay(100)
ForEver
smateja
Beiträge: 250
Registriert: 25.11.2004 19:51
Computerausstattung: Alienware Aurora / Intel Core i7 CPU @ 2.8 GHz / 64 Bit OS

Re: Thread Problematik / mehrere Parallel

Beitrag von smateja »

Hallo ihr zwei.
Danke für die Mithilfe und Verbesserung - läuft soweit 1A und die letzte Stunde Stresstest gab es auch keine Speicherfehler mehr etc. - dafür ein fast Bauchplatzer nach 4 Steaks und n-Bockwursts ;)

Jetzt hab ich allerdings noch eine kleine Frage - die Threads werden ja mit SQL\thread = CreateThread(@Prozess_CPU(), @SQL) erstellt. Mhmm - wie schaff ich es jetzt zu überprüfen ob der Thread läuft bzw. wie kann ich diesen dann abschießen? mit Isthread bin ich gerade bisschen hängen geblieben.

Hintergrund ist der - ich habe 4 Dienste die ich alle einzeln an und abschalten kann. Das geht auch schon. Mit eurer Hilfe habe ich jetzt 4 Threads die dazu da sind, Daten in separaten Graphen zu schreiben (CPU Monitor like). Das klappt natürlich nur - sofern die Dienste an sind - sobald ich die Dienste beende - und ggf. wieder neu starte - verändert sich wohl die PID des jeweiligen Prozesses und ich müsste folglich den Thread killen und neu starten damit wieder Werte in den Graphen einfließen.

Mhmm - für einen weiteren schlag auf den Hinterkopf währe ich dankbar. Alternativ gerne auch Spenden für ne Klimaanlage - denn ich glaub es liegt aktuell echt an meiner Dachzimmer-Wohnung die dank Rechner permanent gefühlte 50 Grad hat.

LG
PB 4.6 / 32 Bit / 64 Bit
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Thread Problematik / mehrere Parallel

Beitrag von ts-soft »

Steht doch alles in den Variablen, z.B.:

Code: Alles auswählen

IsThread(WEB\thread)
KillThread solltest Du aber besser nicht nutzen, sondern eine globale StopVariable auf die ThreadID setzen,
und in der Schleife prüfen ob die StopVariable und thread (*zeit\thread) übereinstimmen und dann die Schleife
verlassen. Ich hoffe mal diese Hinweise bringen Deine Birne zum leuchten ansonsten nachfragen.

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Antworten