The code you found on Internet is really bad. Also, please see my comment to the question.
You should do all the serial port communications in a separate thread; this way, you can close the port in the same thread. Also, I would advise you to use only the blocking calls (synchronous API, none of the asynchronous API). The asynchronous APIs flourished when thread were not such a commonplace as they are now (and even then they were questionable) and internally still use threads or something equivalent, anyway, but do not provide you with enough control. As using synchronous API is more sequential and straightforward, it's more effective, simpler, easier for maintenance and debugging.
Closing of the port per se does not tell anything about it to your microcontroller you have on the other end of the serial cable, so further considerations would need documentation on microcontroller to see how its communication channel behaves on the non-grace closing of the port (which is nothing wrong in principle, but depends on the code of the other side).
In these past answers, I describe how parameters are passed to the thread using a thread wrapper:
How to pass ref parameter to the thread[
^],
change paramters of thread (producer) after it started[
^].
As you are working with UI, it should be isolated from the serial communications. As you need to notify the UI and pass data from the serial port to it, you should use invocation mechanism which allows you to delegate the calls to UI methods and properties to the UI thread, which is the only valid way of working with UI. Please see my past answers for detailed explanations:
You cannot call anything related to UI from non-UI thread. Instead, you need to use the method
Invoke
or
BeginInvoke
of
System.Windows.Threading.Dispatcher
(for both Forms or WPF) or
System.Windows.Forms.Control
(Forms only).
You will find detailed explanation of how it works and code samples in my past answers:
Control.Invoke() vs. Control.BeginInvoke()[
^],
Problem with Treeview Scanner And MD5[
^].
If you want to understand how invocation works, my short article on the inter-thread invocation and blocking queue could be useful:
Simple Blocking Queue for Thread Communication and Inter-thread Invocation[
^].
See also more references on threading:
How to get a keydown event to operate on a different thread in vb.net[
^],
Control events not firing after enable disable + multithreading[
^].
—SA