I did some research and I learned that if I run a program my system will automatically start it in a new thread. What does it look like with a DLL?
Some pseudo-code from a DLL, extern_func() is exported from the DLL:
func1()
{
while(true) ...do something;
}
extern_func()
{
...do something
func1();
...do something else
}
Now if call extern_func() in my program, will it run the function in a new thread or do I have to do this explicitly?
When a program starts, a thread is created. This is usually called the "main" thread.
If you don't explicitly create other threads, or use functions that create other threads, all your code will run in that main thread, even if you call functions that come from a DLL/library.
No, calling a method in another dll will not automatically start up a new thread.
Related
I have a static object that needs to initialize an imaging API. The allocated resources of this imaging API need to be released by the same thread.
So I'm starting a thread in my static object that initializes everything and then waits for a counter to reach zero. When this happens the thread cleans all up and finishes.
This is an unmanaged class inside a managed library, so I can't use System::Threading::Thread (needs a managed static member function) or std::thread (compiler error, not supported with /clr).
So I have to start my thread like:
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&Initialize, this, 0, 0);
All works fine, the init is done and the API functions work. But when I close the application I see that the usage counter of my static object reaches zero but the clean up function is never called by the thread, as if the thread was killed. Is there a way to make sure the thread will continue to exist and execute until its end?
After turning this around in all possible ways and adding events etc I guess this is not possible so I'll have to change the structure of my code and encapsulate the non managed class inside a managed class, and add the thread to the managed class.
I think you could proceed in one of two ways:
Wrap the resources in RAII-style classes, and refactor to have the objects' lifetimes be on the stack of your created thread, ensuring their destructors get called when the thread loop exits without having to call any additional cleanup. If there is no issue with the thread returning correctly when your counter reaches 0, this should be the simplest and cleanest way of addressing this.
I'm thinking you could intercept the WM_CLOSE message using window procedures, process necessary cleanup and then pass the message on, effectively "stalling" it until you are ready to close. Note that even though you are in a DLL you can still set up a window procedure and message pump system, you don't need a GUI to do that. I am however not 100% sure on whether you'll receive the WM_CLOSE message that concerns the application that "owns" your DLL, it's not something I've tried out yet.
You will have to implement some form of messaging through events within your thread's loop however, as the WindowProc will be called on a different thread, so you know when to call the cleanup procedure.
I also am not very familiar with CLR, so there might be a simpler way of interacting with those APIs than with raw C++ calls and handles.
I created a simple singleton and run method in it:
- (void)run {
static int times = 0;
NSLog(#"times = %d", times++);
[self performSelector:#selector(run) withObject:nil afterDelay:MIN_DELAY];
}
But it doesn't work properly. It is executed only once.
But if I replace performSelector:withObject:afterDelay: with performSelector: then it will be called a lot of times (but I need a delay between calls).
So why method performSelector:withObject:afterDelay: doesn't work? And can I use this method at all?
Calls to -performSelector:withObject:afterDelay: require a run loop. Console applications do not, by default, pass control into the run loop ever. For more info, search for NSRunLoop.
From the docs:
This method registers with the runloop of its current context, and depends on that runloop being run on a regular basis to perform correctly.
You have no runloop. Ipso facto, this method does not perform correctly for you.
(Creating and starting a runloop is one of the things that calling UIApplicationMain does, but of course you are never calling it.)
I'm getting to know the NS/Objective-C model of concurrency. Say I have a command line tool that does something like this:
#include "myLibrary.h"
void callback(void* parameter){
cout<<"callback called.\n";
//some logic...
}
int main(int argc, char* argv[]){
myLibraryInit(callback);
std::string s;
while(true){
cin>>s;
myLibrarysResponseTo(s);
}
}
In my library, I'd like to be able to have two responses. One which starts a repeating timer and one which stops it. The timer should call the callback supplied to the library by myLibraryInit.
I've used NSTimers before in iPhone/iPad apps, and I think the problem stems from the different paradigm command line tools have. The main thread goes into main and never finishes it until the program is finished. This means it's not free to run the main run loop, which is what gets the timer going. I think. So how do I make an NSTimer work in this context?
The other thing is that Apple NSTimer documentation says I need to invalidate an NSTimer on the same thread it was installed. I don't know how to figure out what thread I was on when I installed the timer, and then keep track of it (and ensure it stays alive) until I want to invalidate the timer. I'm not sure if I'm just missing an obvious mapping between threads and dispatch queues, run loops, or something else. I am using core bluetooth and I initialize a central manager like so:
_centralManager=[[CBCentralManager alloc]
initWithDelegate: self
queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
];
so a callback may be triggered from here. If the callback includes some logic to call the library function that stops the timer, I can't guarantee from which thread came the invalidate. So how do I properly invalidate the timer?
I found this question but it doesn't allow a main to happen at the same time as the run loop that that the timer is on.
I hope I gave enough context. Thanks in advance for your replies.
You must call dispatch_main() or run an NSRunLoop in the main thread if any of the system frameworks [that use GCD or asynchronous operations] are to work correctly.
This can be as simple as calling [[NSRunLoop currentRunLoop] run]; at the end of your main() function (just make sure you schedule the kickoff work first as that method never returns).
Is there a way for me to hook the exit of managed threads (i.e. run some code on a thread, just before it exits?)
I've developed a mechanism for hooking thread exit that works for some threads. Step 1: develop a 'hook' STA COM class that takes a callback function and calls it in its destructor. Step 2: create a ThreadStatic instance of this object on the thread I want to hook, and pass the object a managed delegate converted to an unmanaged function pointer. The delegate then gets called on thread exit (since the CLR calls IUnknown::Release on all STA COM RCWs as part of thread exit).
This mechanism works on, for example, worker threads that I create in code using the Thread class.
However, it doesn't seem to work for the application's main thread (be it a console or windows app). The 'hook' COM object seems to be deleted too late in the shutdown process and the attempt to call the delegate fails.
(The reason I want to implement this facility is so I can run some native COM code on the exiting thread that works with STA COM objects that were created on the thread, before it's 'too late' (i.e. before the thread has exited, and it's no longer possible to work with STA COM objects on that thread.))
Do you control thread creation? It's probably simplest to simply wrap the thread's code in a try...finally clause, and put your code in the finally.
Note that when the AppDomain shuts down, you can never be sure that your code will be called since the shutdown may be less than graceful.
When you say "Destructor" I presume you mean a C++/CLI destructor - i.e. the .Dispose() method?
If you need to support hooking before the process exits, you could try the AppDomain.CurrentDomain.ProcessExit event - which doesn't seem to fire on an unhandled exception, or AppDomain.CurrentDomain.UnhandledException which seems to fire only on an unhandled exception.
None of this looks particularly robust, mind you...
I have an application in which I am running a separate thread.
Dim thread As New System.Threading.Thread(AddressOf Main)
thread.Start()
However, the thread makes reference to an textbox named Output, and it generates this error upon execution:
System.InvalidOperationException was unhandled
Message="Cross-thread operation not valid: Control 'Output' accessed from a thread other than the thread it was created on."
Source="System.Windows.Forms"
(message shortened for space)
How can I make the operations run on another thread, but still use the Output object? I cannot call a subroutine to do that for me, as it generates the exact same error.
The method called is AppendText, by the way.
I am probably missing something important here, so thanks for the help!
Instead of just calling the AppendText method you need to force it to execute on the correct thread. So, if you have a call like this:
myTextBox.AppendText("some text")
...you need to change it to this:
myTextBox.BeginInvoke(New Action(Of String)(AddressOf myTextBox.AppendText), "some text")
You can use either Invoke or BeginInvoke. In this case, since AppendText doesn't have any return value, BeginInvoke is a good choice (the difference is that Invoke will block the current thread while the GUI thread executes the AppendText method, while BeginInvoke will make the call asynchronously instead).
You should use Control.Invoke or Control.BeginInvoke to call your subroutine.
This exception is a very popular exception when using a thread.Some operation are not thread safe (like accessing a control on a thread other than its own thread) so framework is preventing these kind of problems.
To solve it you can either use Control.Invoke method to call a delegate that is in the same thread the control or you can use a background worker.
Here you can find a sample of first approach
and
Here you can find a sample of a background worker