CLR Tasks (IHostTask and IHostTaskManager)
I have some queries or perhaps misunderstanding about tasks within the CLR. I am writing a CLR Host, which implements an IHostTaskManager. As I understood it, a 'Task' is an abstraction of, in my case, a thread. So whenever the CLR needs to create a thread, it creates an ICLRTask and asks me for the corresponding IHostTask and thread. (If I was using Fibers a Task would in this case be a Fiber not a Thread).
TheCustomising the .Net Framwork Common Language Runtime book indicates that the CLR will not use my task manager if it needs to create certain 'internal' threads (for example) for the garbage collector, a debugger thread, a thread to gate access to the thread pool and a timer thread. So I assume that my IHostTaskManager should never see these threads, and possibly there are other internal CLR requirements that I do not know about from my host.
However, my task manager is being asked to create two tasks before the assembly is loaded. What are these tasks for? After the assembly is loaded I see one more task is created, and to my mind this ought to be the 'main' thread that runs the assembly. I have to admit that I don't yet understand what a managed message pump 'looks like', but I would have thought that the thread I created (at least one of them) would be the one pumping messages for the assembly. Is this not right? Does the host instead pump messages for both the host and the assembly?
If I attempt to suspend the tasks' threads from the unmanaged CLR host, using SuspendThread, then although this appears to succeed (i.e. no errors) the assembly carries on running - you can continue to interact with the dialog and clicking buttons does the stuff it's supposed to. So either SuspendThread isn't doing what I think it should be doing, or the threads I am suspending are not the ones that make the assembly 'work'. If I suspend my host's main thread, then the assembly does appear to stop, but then so do my host so it's a bit suicidal and I don't know exactly the implications of doing this.
For the record, what I am trying to accomplish is to run an assembly (that I do not wish to modify the code of), but which will be entirely subject to my host. If my host needs attention from the user, it needs to be able to suspend the assembly that it is running to force the user to interact with the host rather than ignoring it and carry on using the assembly. Once the host it happy, it should then allow the assembly to continue executing. Can I do this by interacting with the tasks, or do I need to investigate a different approach? (From a Win32 POV, it seemed relatively simple to attach a stub function to an executable, redirect the entry point and be in a position to suspend/resume execution as required, but in managed code it seems frustratingly complex so far....but at least it is fun to learn about new things.)
Thanks in advance again
Jamie
Hi Jamie,
Have you tried to call "SwitchOut" on your ICLRTask in order to change the state of your assembly execution? I don't have my code in front so I don't remember very well, but I though that you can control the task using the switchOut and switchIn.
Also, if you need processor time, you can call "YieldTask", but I think that you need the switch one.
I know that you were asking about IHostTask, but you can assign a CLRTask using "SetCLRTask", this will give you more flexibility and the functionality that i have mentioned.
Sorry if it is not relevant, if this does not work let me know and I will check when I arrive home.
Best regards
Hi
Many thanks for your reply. When I try to suspend the threads the Tasks are running on, I also tried to switch out the tasks first, but this returned E_NOTIMPL on each of the tasks. The ICLRTask object I am using is the one I got from SetCLRTask, so I think this should be the right one. I also tried to make each task yield before asking it to switch out but this also didn't help.
I thought that maybe I am misunderstanding what a 'Task' actually is. I thought the actual assembly would be a Task, and each thread running within the assembly wold be represented as a Task. But my host is creating three and nothing I do to these seems to have any visual impact on the assembly. The only things I can do so far is either Suspend totally or Sleep on the main thread in the host, which in turn seems to stop the assembly - like the assembly is running on the hosts main thread not one of the Task threads I have created for it.
So perhaps, are Tasks only used for additional threads created manually within the assembly (System.Threading) that are not created within a thread pool? And the assembly's 'main thread' is not represented as a Task? What are the three Tasks, I am asked to create, actually used for?
I shall have to keep digging I think. Maybe I'll need to create some more complex assemblies with debugging information to run with my host to see how the interact together. I have a lot of experience with unmanaged code, but compartively little with managed code so there is a lot to take in at first - and I suppose it doesn't help that I am trying to start at the deep end!
Thanks
Jamie
Hi Jamie,
It is correct, a task is an abstraction of the underlying unit of execution (a thread or a fiber). The HostTask is the host control of the task, and the CLRTask is the CLR one.
As soon as you create a task the CLR creates some management threads responsible for tasks like garbage collection, threadpool and internal timers.
But to save you some headaches I am copying a link that you will find quite interesting (maybe you already knows about it but I have used as a guidence on my project). If this blog does not help you please write me back on this thread and I will be able to help you if we exchange some code.
http://community.bartdesmet.net/blogs/bart/archive/category/45.aspx
(on the link you can see that is divided in parts, part 4 talks about threading and schedulling)
Hope this helps and don't hesitate to contact the forum again to find the answers :)
Best regards
Hi Salvador
Thanks for all your input. I read that B# blog before but it just seems to say the same things as the CLR book I have. I thought I understood what it was talking about, but I can't relate what I have read about with what I am actually seeing. These question is slightly more academic now as I managed to be able to work around my problem of preventing users using the assembly when my host needs input instead, so in those terms I am happy. But now I am more curious about the Tasks because they didn't seem to help me at all, and I'd like to actually understand what a Task actually is in real terms, and what it is being used for, for my own knowledge.
My test assembly has so far been just a very simple C# program with a dialog and a button that displays a "Hello World" message box when it's clicked. I imagine this needs only a single thread to operate. When I host the CLR, the CLR first asks me to create two Tasks. Then it asks my IHostAssemblyStore for the assembly which I provide and then it asks me to create a third Task. The last of these Tasks I originally assumed to be the "main thread" for my assembly. But none of the ICLRTask objects allow me to SwitchOut the Task and suspending the threads of these Tasks has no noticable impact on the assembly, and it will keep running even after I have called SuspendThread (and this does not indicate an error). Instead it seems that the assembly is running on the main thread of my host - this is the only thread I can do something to that then has an impact on the assembly itself. Because of this behaviour, it raises several questions in my mind about what actually is going on "behind the scenes".
Perhaps my problem is that I am trying to think about the managed world in Win32 terms. I assumed originally that there is some form of message pump that handles the dialog refresh and control messages etc. And I thought that the Task I was being asked to create would be for the thread that ran through this message pump. But in reality the assemblies do not appear to work this way, so I assume now that the Tasks are only for additonal threads that the programmer has manually created, and that are not created from a threadpool (because there is different interface for the thread pool). But it seems Tasks are not created for the 'main thread' (which is probably a bad way to describe it) and all control messages and refresh messages etc are handled in some other way. I think I shall have to do some more investigations with some multi threaded assemblies and trying to host multiple assemblies within the same host to get to the bottom of what is happening "behind the scenes".
Jamie