Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Thread helper class

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Extensions
View previous topic :: View next topic  
Author Message
DaSpamer
Grandmaster Cheater Supreme
Reputation: 30

Joined: 13 Sep 2011
Posts: 1499

PostPosted: Fri Mar 06, 2020 11:29 am    Post subject: Thread helper class Reply with quote

Some threads helper class I wrote some time ago..
Might come handy when fetching information or running some task in background and what so..
save and place in auto run or include into your project
Code:
threadClass = {};
local ti,tr = table.insert,table.remove;
setmetatable(threadClass, {
   __call = function (cls, ...)
      return threadClass.new(...);
   end,
})

function threadClass.new(init)
   local totalThreads = 0;
   local self = setmetatable({}, {
      __call = function (cls, ...)
         print("total threads #",tostring(totalThreads));
      end
   })
   self.__index = self;
   self.threads = {};
   self.suspended = false;
   local callback = function(thread,id)
      self.doQueue(id,thread);
   end
   self.createThread = function(id)
      if(not id or (tonumber(id) and self.threads[id])) then -- we must assign id for the thread, and make sure that id is not used --> if used obtain new id for us
         local _id = 0;
         while true do
            _id = _id + 1;
            if (not self.threads[_id]) then
               id = _id;
               break;
            end
         end
      end
      local thread = createNativeThreadSuspended(function (thread) callback(thread,id) end);
      thread.name = "Thread helper #"..id;
      self.threads[id] = {id = id, thread = thread,suspended = true,start = os.clock(), queue = {}};
      local tthreads = self.threads[id];
      tthreads.getId = function () return id end;
      tthreads.hasQueue = function () return self.hasQueue(id) end;
      tthreads.getQueue = function () return tthreads.queue end;
      tthreads.suspendThread = function () thread.suspend(); tthreads.suspended = true; return true; end;
      tthreads.resumeThread = function () thread.resume(); tthreads.suspended = false; return true; end;
      tthreads.destroyThread = function () return self.destroyThread(id) end;
      tthreads.destroyQueue = function () return self.destroyQueue(id) end;
      tthreads.addQueue = function (func) return self.addQueueEx(id,func); end;
      tthreads.doQueue = function() tthreads.resumeThread(); return end;
      totalThreads = totalThreads + 1;
      return self.threads[id],id;
   end
   self.getTotalThreads = function()
      return totalThreads;
   end
   self.getThreadById = function(id)
      return self.threads[id] or nil;
   end
   self.getIdByThread = function(thread)
      if (not thread) then
         return nil;
      end
      for id,threadObj in pairs(self.threads) do
         if (threadObj.thread == thread) then
            return id;
         end
      end
      return false;
   end
   self.AutoCreateThreads = function()
      local total = (os.getenv("NUMBER_OF_PROCESSORS")//2 or 1);
      for i=1,total do
         self.createThread();
      end
   end
   self.getActive = function ()
      return not self.suspended;
   end
   self.setActive = function (state)
      if (type(state)=='boolean') then
         self.suspended = not state;
      else
         self.suspended = not self.suspended;
      end
      if (self.suspended) then
         return self.SuspendAllThreads();
      else
         return self.ResumeAllThreads();
      end
   end
   self.SuspendAllThreads = function()
      for k,v in pairs(self.threads) do
         if (not v.suspended) then
            v.thread.suspend();
            v.suspended = true;
         end
      end
      return true;
   end
   self.hasQueue = function(id)
      return self.getQueueSize(id) > 0;
   end
   self.getQueueSize = function(id)
      local threadObj = self.threads[id];
      if (not (threadObj and threadObj.queue)) then
         return 0;
      end
      return #threadObj.queue;
   end
   self.ResumeAllThreads = function()
      for k,v in pairs(self.threads) do
         if (v.suspended and self.hasQueue(v.id)) then
            v.suspended = false;
            v.thread.resume();
         end
      end
      return true;
   end
   self.destroy = function(force)
      if (force) then
         self.SuspendAllThreads();
         for k,v in pairs(self.threads) do
            pcall(v.thread.terminate);
         end
         self.threads = {};
         totalThreads = 0;
         return true;
      end
      for id,threadObj in pairs(self.threads) do
         if (self.destroyThread(id)) then
            totalThreads = totalThreads-1
         end
      end
      return totalThreads == 0;
   end
   self.doQueue = function(id,thread)
      local threadObj = self.threads[id];
      if (not (threadObj and threadObj.queue)) then
         return false;
      end
      local queue = threadObj.queue;
      while true do
         local func = queue[1];
         if (func and type(func)=='function') then
            pcall(func,threadObj.thread,id);
            tr(queue,1);
         elseif(func == "__exit") then
            tr(queue,1);
            self.threads[id] = nil;
            totalThreads = totalThreads - 1;
            -- if thread then
               -- thread.terminate();
            -- end
            break;
         elseif(not threadObj.suspended) then
            threadObj.suspended = true;
            threadObj.thread.suspend();
            -- break;
         elseif(inMainThread()) then -- Calling this function directly from main thread, without resuming worker thread will cause infinite loop.
            break;
         end
      end
      -- self.destroyThread(id);
   end
   self.destroyQueue = function(id)
      local threadObj = self.threads[id];
      if (not (threadObj and threadObj.queue)) then
         return false;
      end
      local shouldresume = false;
      if(not threadObj.suspended) then
         shouldresume = true;
         threadObj.thread.suspend();
      end
      for key in pairs(threadObj.queue) do
         threadObj.queue[key] = nil;
      end
      if (shouldresume) then
         threadObj.thread.resume();
      end
      return true;
   end
   self.destroyThread = function(id)
      local threadObj = self.threads[id];
      if (not (threadObj and threadObj.thread)) then
         return false;
      end
      return (self.destroyQueue(id) and self.addQueueEx(id,"__exit"));
   end
   self.addQueueEx = function(id,func)
      local threadObj = self.threads[id];
      if (not (func and threadObj and threadObj.thread)) then
         return false;
      end
      ti(threadObj.queue,func);
      if (threadObj.suspended and not self.suspended) then
         threadObj.suspended = false;
         threadObj.thread.resume();
      end
      return true;
   end

   self.addQueue = function(func)
      local id,total;
      for _id,threadObj in pairs(self.threads) do
         if (threadObj.suspended and not self.suspended) then
            id = _id;
            break;
         elseif((not total) or self.getQueueSize(_id) < total) then
            total = self.getQueueSize(_id);
            id = _id;
         end
      end
      return self.addQueueEx(id,func);
   end
   return self;
end
return threadClass;



Some example usage and explanation
Code:
--[[
threadClass(); --> returns threads class object
Methods:
obj.createThread(id) : thread; assigned id --> id is optinal
obj.getTotalThreads() : integer
obj.getThreadById(id) : integer
obj.getIdByThread(thread) : integer
obj.AutoCreateThreads() : nil
obj.doQueue(id) : nil --> should not be used! only for debugging purposes
obj.destroy(force) : boolean --> destroys all threads, does not destroy the class
obj.destroyQueue(id) : boolean
obj.destroyThread(id) : boolean
obj.addQueueEx(id,func) : boolean
obj.addQueue(func) : boolean
obj.setActive(state) : boolean -->suspends/resumes all threads (threads with no queue won't be resumed)
obj.getActive() : boolean -->status if class is active, all threads are suspended or resumed
obj.SuspendAllThreads() : boolean --> adding new queue will resume, unlike setActive(false) which will not resume anythread unless thread.resumeThread() or class.ResumeAllThreads() is called
obj.ResumeAllThreads() : boolean
obj.hasQueue(id) : boolean
--]]
--[[
-- Usage
threads = threadClass();
threads(); --> total threads # 0
threads.AutoCreateThreads(); -- creates threads half of the the cpu threads count
threads(); --> total threads # 4; on desktop i7-4970k
-- threads.addQueue(function()
   -- action that you wish to do
   -- do not forget to use synchronize if it's GUI related
-- end);
-- threads.destroyThread(4) --> destroys last thread


-- ###Example###
-- the following script will add useless actions for the threads
-- the action contains sleep to delay and allow the script to assign the next action to the least queued thread
t = createTimer(nil)
t.Interval = 50;
v={}
local i = 0;
t.onTimer = function()
   i=i+1;
   threads.addQueue(function (thread,id) _x = (_x or 0) + 1; print("COUNT ",_x,", ID - ",id); sleep(math.random(100,500)*(id));
   v[id] = (v[id] or 0)+1; --> total count of calls ordered by ID
   end)
   if(i>=50)then
      t.destroy(); -->destroy timer
   end
end

-- now running this as soon as it's finished running all events (we have to wait or write a function that holds the thread until all other are finished)
for k,v in pairs(v) do
    print("id ",k," = ",v);
end
-- output I got for running the script above, since the higher the id the higher the delay (delay sum is randomized and multiplied by id)
-- id  1  =  17
-- id  2  =  12
-- id  3  =  11
-- id  4  =  10
-- rerunning the script output me this
-- id  1  =  17
-- id  2  =  13
-- id  3  =  10
-- id  4  =  10
-- increasing timerInterval (causing higher delay between queue placement but allows threads to reduce the queue size drastically)
-- to 150(3x more delay) yields this output
-- thread 4 takes at most 4x more time to execute comparing to thread 1, thats why thread 1 executed 4.333x more commands
-- id  1  =  26
-- id  2  =  10
-- id  3  =  8
-- id  4  =  6
--]]

Additional example;
Code:

local threads = myThreads
threads.getThreadById(1).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(1).queue); end)
threads.getThreadById(2).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(2).queue); end)
threads.getThreadById(1).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(1).queue); end)
threads.getThreadById(2).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(2).queue); end)
threads.getThreadById(1).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(1).queue); end)
threads.getThreadById(2).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(2).queue); end)
threads.getThreadById(1).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(1).queue); end)
threads.getThreadById(2).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(2).queue); end)
threads.getThreadById(1).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(1).queue); end)
threads.getThreadById(2).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(2).queue); end)
threads.getThreadById(1).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(1).queue); end)
threads.getThreadById(2).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(2).queue); end)
threads.getThreadById(1).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(1).queue); end)
threads.getThreadById(2).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(2).queue); end)
threads.getThreadById(1).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(1).queue); end)
threads.getThreadById(2).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(2).queue); end)
threads.SuspendAllThreads(); -- suspends all the threads; any queue added afterwards will resume a thread;
threads.getThreadById(1).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(1).queue); end)
threads.getThreadById(2).addQueue(function (thread,threadid) for i=1,15 do sleep(math.random(1,100)*threadid); print("Test",threadid,'\t', os.clock()); end; print('Thread -',threadid,'   queue left=',#threads.getThreadById(2).queue); end)
--]]

_________________
HEY Hitler
Do you get lazy when making trainers?
Well no more!
My CETrainer will generate it for you in seconds, so you won't get lazy! Very Happy

http://forum.cheatengine.org/viewtopic.php?t=564919
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Extensions All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites