multithreading - How to implement a List(of Task) functions as a queue? (VB.NET) -
as simple can:
multi-thread wpf window app. all threads query single device via ssh. device can have multiple same-users, io stack won't allow app (obviously).
trying inquire 'legal' way:
how can create queue (fifo) of tasks/actions each homecoming string function?
2014-06-21 update
this now. can create tasks on concurrentqueue.
the issue remains how modify allow task created/called, task set fifo queue, , tasks's result (string) returned variable called it, like:
dim result = task...("the command")...
the below foundation testing ways (compiles & runs):
dim tcq new concurrentqueue(of task) sub main() ' simulates programme calls enqueue tasks on tcq: = 1 20 tcq.enqueue(gettask(date.now.tolongtimestring & " - command number " & i)) next ' normally, tcq watched in loop while tcq.count > 0 dim tsk task = nil tcq.trydequeue(tsk) tsk.wait() console.writeline(date.now.tolongtimestring & " [" & tsk.id & "] post-wait(): " & tsk.id & " tcq.count: " & tcq.count) loop console.writeline("done.") console.readline() end sub
this next function creates task command string in it...
function gettask(commandstring string) task(of string) dim t task(of string) = nil dim cts new cancellationtokensource() dim ct cancellationtoken = cts.token seek t = task(of string).factory.startnew(function() homecoming getcommandresults(commandstring, ct) end function, ct, taskcreationoptions.longrunning) t.wait() console.writeline("gettask.id: " & t.id & " result: " & t.result) grab ex exception console.writeline("caught exception: " & ex.tostring) end seek homecoming t end function
this function sending command device, , storing response string well...
function getcommandresults(thecommand string, ct cancellationtoken) string console.writeline(string.format("--> starting getcommandresults({0})", thecommand)) thread.sleep(2000) console.writeline(string.format("<-- done getcommandresults({0})", thecommand)) homecoming string.format(date.now.tolongtimestring & " - getcommandresults returned {0}", thecommand) end function
and yields:
[main()] before creating tasks --> starting getcommandresults(8:14:38 pm - command number 1) <-- done getcommandresults(8:14:38 pm - command number 1) gettask.id: 1 result: 8:14:40 pm - getcommandresults returned 8:14:38 pm - command number 1 --> starting getcommandresults(8:14:40 pm - command number 2) <-- done getcommandresults(8:14:40 pm - command number 2) gettask.id: 2 result: 8:14:42 pm - getcommandresults returned 8:14:40 pm - command number 2 --> starting getcommandresults(8:14:42 pm - command number 3) <-- done getcommandresults(8:14:42 pm - command number 3) gettask.id: 3 result: 8:14:44 pm - getcommandresults returned 8:14:42 pm - command number 3 [...]
so if had write out logically:
a string variable prepared output of created task, using command string. the string command set concurrentqueue. when task dequeued concurrentqueue, run, , result of command returned calling variable.
so, i'm looking way this, described above synchronous queue:
dim result string = await task.factory.startnew(function() dim r string = functionthatreturnsstring() homecoming r end function)
...except can't seem stop tasks executing created...
hope update helps!
no improve way propose solution. since there hasn't been action on (no points tough question, even), hope moderators other way inquire how made better-but without question marks!
to sum solution effort up:
the caller either creates or uses singleton jobqsingleton().
the caller uses q creating unique guid (for looking results later), , job string:
dim jobid guid = guid.newguid dim mycommand string = "command job #" & i
the caller creates job() instance, loads above params, , submits q:
dim j job = new job() j.callerjobid = jobid j.command = mycommand j.callername = "caller #" & thejobq.jobrequest(j)
lastly, caller waits on result calling getjobresultasync() on thejobq, using guid supplied job when submitted 'index', if will, locate results:
dim jobresult string = thejobq.getjobresultasync(callerjobid).result
the working illustration here, leaves many questions in mind, big 1 beingness whether putting tasks on queue qould better, la:
dim t new task(addressof me.takefromqloop, ct, taskcreationoptions.longrunning) ...add queue; when time, pull off queue and... t.start()
for discussion: cannot find way maintain tasks attached callers pass into/out of q. doing might lot less convoluted. hinted @ in op.
luckily, wrote test/use case in 1 module easy copy/pasting. works in vs2012:
imports system.collections.concurrent module module1 dim thejobq jobqsingleton ' sub main() thejobq = jobqsingleton.getinstance ' 1 class can work (serially/synchronously) ' ' step 1: create jobs ' dim joblist new concurrentqueue(of job) ' each client comes own guid later retriece job's results dim jobidlist new concurrentqueue(of guid) ' list holds guid, can iterate @ end , results = 1 10 dim jobid guid = guid.newguid dim mycommand string = "command job #" & console.writeline("[{0}] callerjobid: {1} command: {2}", i, jobid.tostring, mycommand) joblist.enqueue(new job() {.callerjobid = jobid, .command = mycommand, .callername = "caller #" & i}) jobidlist.enqueue(jobid) next ' ' step 2: submit requests ' threading.thread.sleep(1000) each jreq job in joblist if joblist.trydequeue(jreq) thejobq.jobrequest(jreq) end if console.writeline("[{2}] {0} added {1} q via .jobrequest", jreq.callername, jreq.callerjobid, joblist.count) next ' ' step 3: results (using retrieveq created before copying joblist) ' each clientjobid guid in jobidlist '.reverse ' simulates our clients' provided guids dim jobresult string = getworkresult(clientjobid) console.writeline("result of client jobid: {0} is: ""{1}""", clientjobid, jobresult, jobidlist.count) next console.writeline("done.") console.readline() end sub ' ' step 3a: ' public function getworkresult(callerjobid guid) string dim r string = "" r = thejobq.getjobresultasync(callerjobid).result homecoming r end function ' '======================================================================== ' ' jobq() ' public class jobqsingleton #region "class vars" ' singleton instance shared myinstance jobqsingleton ' requests private q new concurrentqueue(of job) ' results private resultsdictionary new concurrentdictionary(of guid, job) private doqloop boolean #end part #region "constructor" private sub new() me.doqloop = true me.startloop() end sub public shared function getinstance() jobqsingleton if isnothing(myinstance) myinstance = new jobqsingleton end if homecoming myinstance end function private sub startloop() dim cts new threading.cancellationtokensource dim ct threading.cancellationtoken = cts.token ' (a) .start(): 'dim t new task(addressof me.takefromqloop, ct, taskcreationoptions.longrunning) 't.start() ' (b) simple addressof: dim t task = task.factory.startnew(addressof me.takefromqloop, ct, taskcreationoptions.longrunning) ' console.writeline("loop started") end sub #end part #region "(public) submit/retrieve jobs" '======================================================= ' ' step 2a: add together guid internal use/deugging ' public sub jobrequest(ajobrequest job) ajobrequest .qjobid = guid.newguid ' our internal id end me.addjob(ajobrequest) end sub public async function getjobresultasync(byval jobid guid) task(of string) homecoming await task.run(of string)(function() getjobresult(jobid)) end function ' ' callers phone call 1 of above 2 either give job, or results ' '======================================================= private function getjobresult(jobid guid) string until me.resultsdictionary.containskey(jobid) threading.thread.sleep(250) loop homecoming me.resultsdictionary.item(jobid).response end function #end part private sub addjob(j job) q.enqueue(j) end sub private sub takefromqloop() while (me.doqloop) dim j new job if q.trypeek(j) = true if q.trydequeue(j) = true j console.writeline("===> start job id {0} caller {1}", .callerjobid, .callername) threading.thread.sleep(1000) j.response = string.format("the result of command {0} {1}", j.command, date.now.tolongtimestring) if me.resultsdictionary.tryadd(j.callerjobid, j) console.writeline("<=== stop job id {0} caller {1}", .callerjobid, .callername) else console.writeline("...error...") end if end end if end if threading.thread.sleep(1000) end while end sub end class ' ' holds job & results... ' public class job public property jobname string public property qjobid guid public property callername string public property callerjobid guid public property command string public property response string end class end module
output (not using .reverse alternative commented out above)
loop started [1] callerjobid: d4a1f479-1d27-4b2f-8d9c-5db1fbacf906 command: command job #1 [2] callerjobid: 06a4a886-4054-426b-b963-88e54d4aeda7 command: command job #2 [3] callerjobid: 1415bb08-607c-4bf0-9b28-a1f33eb24c33 command: command job #3 [4] callerjobid: 18568325-ce4e-4ece-aeff-4f03b20567bf command: command job #4 [5] callerjobid: adaffd34-8c76-48eb-a9e3-dbbf3d7cfd1f command: command job #5 [6] callerjobid: fabc4ae2-681c-44fa-be83-24c185fc6a54 command: command job #6 [7] callerjobid: 7532a8f8-8f97-471a-914b-e1dd9cc88f29 command: command job #7 [8] callerjobid: 433338db-94d3-41c1-a003-f883a57059ca command: command job #8 [9] callerjobid: b1a47e95-c48c-4b36-b6eb-1c582148d564 command: command job #9 [10] callerjobid: 63707629-2140-431b-a91f-13f0b8a37239 command: command job #10 [9] caller #1 added d4a1f479-1d27-4b2f-8d9c-5db1fbacf906 q via .jobrequest [8] caller #2 added 06a4a886-4054-426b-b963-88e54d4aeda7 q via .jobrequest [7] caller #3 added 1415bb08-607c-4bf0-9b28-a1f33eb24c33 q via .jobrequest [6] caller #4 added 18568325-ce4e-4ece-aeff-4f03b20567bf q via .jobrequest [5] caller #5 added adaffd34-8c76-48eb-a9e3-dbbf3d7cfd1f q via .jobrequest [4] caller #6 added fabc4ae2-681c-44fa-be83-24c185fc6a54 q via .jobrequest [3] caller #7 added 7532a8f8-8f97-471a-914b-e1dd9cc88f29 q via .jobrequest [2] caller #8 added 433338db-94d3-41c1-a003-f883a57059ca q via .jobrequest [1] caller #9 added b1a47e95-c48c-4b36-b6eb-1c582148d564 q via .jobrequest [0] caller #10 added 63707629-2140-431b-a91f-13f0b8a37239 q via .jobrequest ===> start job id d4a1f479-1d27-4b2f-8d9c-5db1fbacf906 caller caller #1 <=== stop job id d4a1f479-1d27-4b2f-8d9c-5db1fbacf906 caller caller #1 result of client jobid: d4a1f479-1d27-4b2f-8d9c-5db1fbacf906 is: "the result of command command job #1 7:27:41 pm" ===> start job id 06a4a886-4054-426b-b963-88e54d4aeda7 caller caller #2 <=== stop job id 06a4a886-4054-426b-b963-88e54d4aeda7 caller caller #2 result of client jobid: 06a4a886-4054-426b-b963-88e54d4aeda7 is: "the result of command command job #2 7:27:43 pm" ===> start job id 1415bb08-607c-4bf0-9b28-a1f33eb24c33 caller caller #3 <=== stop job id 1415bb08-607c-4bf0-9b28-a1f33eb24c33 caller caller #3 result of client jobid: 1415bb08-607c-4bf0-9b28-a1f33eb24c33 is: "the result of command command job #3 7:27:45 pm" ===> start job id 18568325-ce4e-4ece-aeff-4f03b20567bf caller caller #4 <=== stop job id 18568325-ce4e-4ece-aeff-4f03b20567bf caller caller #4 result of client jobid: 18568325-ce4e-4ece-aeff-4f03b20567bf is: "the result of command command job #4 7:27:47 pm" ===> start job id adaffd34-8c76-48eb-a9e3-dbbf3d7cfd1f caller caller #5 <=== stop job id adaffd34-8c76-48eb-a9e3-dbbf3d7cfd1f caller caller #5 result of client jobid: adaffd34-8c76-48eb-a9e3-dbbf3d7cfd1f is: "the result of command command job #5 7:27:49 pm" ===> start job id fabc4ae2-681c-44fa-be83-24c185fc6a54 caller caller #6 <=== stop job id fabc4ae2-681c-44fa-be83-24c185fc6a54 caller caller #6 result of client jobid: fabc4ae2-681c-44fa-be83-24c185fc6a54 is: "the result of command command job #6 7:27:51 pm" ===> start job id 7532a8f8-8f97-471a-914b-e1dd9cc88f29 caller caller #7 <=== stop job id 7532a8f8-8f97-471a-914b-e1dd9cc88f29 caller caller #7 result of client jobid: 7532a8f8-8f97-471a-914b-e1dd9cc88f29 is: "the result of command command job #7 7:27:53 pm" ===> start job id 433338db-94d3-41c1-a003-f883a57059ca caller caller #8 <=== stop job id 433338db-94d3-41c1-a003-f883a57059ca caller caller #8 result of client jobid: 433338db-94d3-41c1-a003-f883a57059ca is: "the result of command command job #8 7:27:55 pm" ===> start job id b1a47e95-c48c-4b36-b6eb-1c582148d564 caller caller #9 <=== stop job id b1a47e95-c48c-4b36-b6eb-1c582148d564 caller caller #9 result of client jobid: b1a47e95-c48c-4b36-b6eb-1c582148d564 is: "the result of command command job #9 7:27:57 pm" ===> start job id 63707629-2140-431b-a91f-13f0b8a37239 caller caller #10 <=== stop job id 63707629-2140-431b-a91f-13f0b8a37239 caller caller #10 result of client jobid: 63707629-2140-431b-a91f-13f0b8a37239 is: "the result of command command job #10 7:27:59 pm" done.
...and time with .reverse uncommented:
loop started [1] callerjobid: 596de3ee-04e2-49dd-aaeb-e4a2aa41c90a command: command job #1 [2] callerjobid: cbf0ab0d-5637-4708-837b-3bf7d605f6e1 command: command job #2 [3] callerjobid: d8ba30c6-7729-4f91-8d86-51dfbf3b4b3f command: command job #3 [4] callerjobid: 292d6212-de33-471a-9fdc-dad8b4bef4d4 command: command job #4 [5] callerjobid: 992af5e4-a713-400c-9792-578ac39c6879 command: command job #5 [6] callerjobid: f87a09fa-8cba-4d56-9658-567f0ef6d63e command: command job #6 [7] callerjobid: fc7a1f0c-1a75-44ce-93bf-dc80d6c810c7 command: command job #7 [8] callerjobid: 01d6af2c-5998-4b38-9244-006e9e12f309 command: command job #8 [9] callerjobid: cae99dd9-e7e2-4614-be5b-a75d944e27bd command: command job #9 [10] callerjobid: 3f02a3bb-5667-48fb-ab22-df8d951b2b13 command: command job #10 [9] caller #1 added 596de3ee-04e2-49dd-aaeb-e4a2aa41c90a q via .jobrequest [8] caller #2 added cbf0ab0d-5637-4708-837b-3bf7d605f6e1 q via .jobrequest [7] caller #3 added d8ba30c6-7729-4f91-8d86-51dfbf3b4b3f q via .jobrequest [6] caller #4 added 292d6212-de33-471a-9fdc-dad8b4bef4d4 q via .jobrequest [5] caller #5 added 992af5e4-a713-400c-9792-578ac39c6879 q via .jobrequest [4] caller #6 added f87a09fa-8cba-4d56-9658-567f0ef6d63e q via .jobrequest [3] caller #7 added fc7a1f0c-1a75-44ce-93bf-dc80d6c810c7 q via .jobrequest [2] caller #8 added 01d6af2c-5998-4b38-9244-006e9e12f309 q via .jobrequest [1] caller #9 added cae99dd9-e7e2-4614-be5b-a75d944e27bd q via .jobrequest [0] caller #10 added 3f02a3bb-5667-48fb-ab22-df8d951b2b13 q via .jobrequest ===> start job id 596de3ee-04e2-49dd-aaeb-e4a2aa41c90a caller caller #1 <=== stop job id 596de3ee-04e2-49dd-aaeb-e4a2aa41c90a caller caller #1 ===> start job id cbf0ab0d-5637-4708-837b-3bf7d605f6e1 caller caller #2 <=== stop job id cbf0ab0d-5637-4708-837b-3bf7d605f6e1 caller caller #2 ===> start job id d8ba30c6-7729-4f91-8d86-51dfbf3b4b3f caller caller #3 <=== stop job id d8ba30c6-7729-4f91-8d86-51dfbf3b4b3f caller caller #3 ===> start job id 292d6212-de33-471a-9fdc-dad8b4bef4d4 caller caller #4 <=== stop job id 292d6212-de33-471a-9fdc-dad8b4bef4d4 caller caller #4 ===> start job id 992af5e4-a713-400c-9792-578ac39c6879 caller caller #5 <=== stop job id 992af5e4-a713-400c-9792-578ac39c6879 caller caller #5 ===> start job id f87a09fa-8cba-4d56-9658-567f0ef6d63e caller caller #6 <=== stop job id f87a09fa-8cba-4d56-9658-567f0ef6d63e caller caller #6 ===> start job id fc7a1f0c-1a75-44ce-93bf-dc80d6c810c7 caller caller #7 <=== stop job id fc7a1f0c-1a75-44ce-93bf-dc80d6c810c7 caller caller #7 ===> start job id 01d6af2c-5998-4b38-9244-006e9e12f309 caller caller #8 <=== stop job id 01d6af2c-5998-4b38-9244-006e9e12f309 caller caller #8 ===> start job id cae99dd9-e7e2-4614-be5b-a75d944e27bd caller caller #9 <=== stop job id cae99dd9-e7e2-4614-be5b-a75d944e27bd caller caller #9 ===> start job id 3f02a3bb-5667-48fb-ab22-df8d951b2b13 caller caller #10 <=== stop job id 3f02a3bb-5667-48fb-ab22-df8d951b2b13 caller caller #10 result of client jobid: 3f02a3bb-5667-48fb-ab22-df8d951b2b13 is: "the result of command command job #10 7:30:12 pm" result of client jobid: cae99dd9-e7e2-4614-be5b-a75d944e27bd is: "the result of command command job #9 7:30:10 pm" result of client jobid: 01d6af2c-5998-4b38-9244-006e9e12f309 is: "the result of command command job #8 7:30:08 pm" result of client jobid: fc7a1f0c-1a75-44ce-93bf-dc80d6c810c7 is: "the result of command command job #7 7:30:06 pm" result of client jobid: f87a09fa-8cba-4d56-9658-567f0ef6d63e is: "the result of command command job #6 7:30:04 pm" result of client jobid: 992af5e4-a713-400c-9792-578ac39c6879 is: "the result of command command job #5 7:30:02 pm" result of client jobid: 292d6212-de33-471a-9fdc-dad8b4bef4d4 is: "the result of command command job #4 7:30:00 pm" result of client jobid: d8ba30c6-7729-4f91-8d86-51dfbf3b4b3f is: "the result of command command job #3 7:29:58 pm" result of client jobid: cbf0ab0d-5637-4708-837b-3bf7d605f6e1 is: "the result of command command job #2 7:29:56 pm" result of client jobid: 596de3ee-04e2-49dd-aaeb-e4a2aa41c90a is: "the result of command command job #1 7:29:54 pm" done.
p.s. yes, did utilize terms 'job' , 'work' , 'request' synonymously... was/is frankenstein... p.s.s. did not include deleting dictionary entries contain solutions 1 time 'picked up'... not until peer feedback tidy things up...
i'm not allowed end solution post question mark, have imagine there...
vb.net multithreading