473,395 Members | 1,730 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

VB.NET Threaded DLL

Hi,

I've been trying to create a multithreaded dll to be used for simple
error logging to a file. The DLL will need to be imported into a .NET
framework based application (Wonderware). I am having a problem
importing into wonderware, getting the error message "...Denotes a
field where a class was expected".

I carry out the threading using the Mutex object, can this be used in a
DLL class? It also imports System.IO and System.Threading - could this
be a factor?

The DLL seems to work when I use a dummy VB application to call it -
although it does get the logging mixed up (i.e. time not in sequence)
but it does prevent any file locking errors.

The structure of the class is as follows:

Public Class logMessageToFile
Private Shared FileLockMutex As New Mutex
Private Class loggerClass
Public strMessageText As String
*Some more public vars declared here*
Public Sub LogMessage()
* use mutex here*
* log messages to file*
* release mutex *
End sub
End Class
Public Shared Sub writeToLog(ByVal MsgText As String, *other params*)
Dim cLog As New loggerClass
Dim thread1 As System.Threading.Thread
thread1 = New Threading.Thread(AddressOf cLog.LogMessage)
cLog.strMessageText = MsgText
* store other params*
thread1.Start()
End sub
End class

As you can see I had difficulty ensuring that the variables remained
private to each thread so I [thought] had to use a class to store them.
If anyone can see any issues as to why this wouldn't work then let me
know and I will resolve them and try again in wonderware.

Thanks in advance,

Colly Mitchell

Mar 28 '06 #1
7 3677
Colly,

It doesn't sound like the error message has anything to do with
threading to me. When do you get the message? Is it when you
reference the assembly from Wonderware? Is it in code that you've
written inside Wonderware?

Also, I don't think the use of threads is appropriate here. You're
creating a new thread on each and every log message. That's going to
be slow. You probably don't need to use threads at all. Writing to
the file should be very quick. If you still think you need
asynchronous processing of log messages then I recommend using a single
thread. That thread would more or less sit in an infinite loop waiting
for log messages to appear in a queue. It would dequeue them one at a
time and stick them in a file serially. Your writeToLog method would
simply enqueue the message.

Another thing, if you need to synchronize access to a shared resource
the SyncLock keyword or Monitor class is usually better than using a
Mutex. The Mutex is intended for use cases involving the
synchronization of multiple processes.

You can't make variables or classes private to thread. It just doesn't
work that way. You can simulate it by using thread local storage
though.

Brian

CollyMitch wrote:
Hi,

I've been trying to create a multithreaded dll to be used for simple
error logging to a file. The DLL will need to be imported into a .NET
framework based application (Wonderware). I am having a problem
importing into wonderware, getting the error message "...Denotes a
field where a class was expected".

I carry out the threading using the Mutex object, can this be used in a
DLL class? It also imports System.IO and System.Threading - could this
be a factor?

The DLL seems to work when I use a dummy VB application to call it -
although it does get the logging mixed up (i.e. time not in sequence)
but it does prevent any file locking errors.

The structure of the class is as follows:

Public Class logMessageToFile
Private Shared FileLockMutex As New Mutex
Private Class loggerClass
Public strMessageText As String
*Some more public vars declared here*
Public Sub LogMessage()
* use mutex here*
* log messages to file*
* release mutex *
End sub
End Class
Public Shared Sub writeToLog(ByVal MsgText As String, *other params*)
Dim cLog As New loggerClass
Dim thread1 As System.Threading.Thread
thread1 = New Threading.Thread(AddressOf cLog.LogMessage)
cLog.strMessageText = MsgText
* store other params*
thread1.Start()
End sub
End class

As you can see I had difficulty ensuring that the variables remained
private to each thread so I [thought] had to use a class to store them.
If anyone can see any issues as to why this wouldn't work then let me
know and I will resolve them and try again in wonderware.

Thanks in advance,

Colly Mitchell


Mar 28 '06 #2
Brian,

Firstly thank-you for your feedback.

I get the message when it tries to compile.

The reason I had used a threaded solution was because the process could
only take a maximum of 500msec and a slow logging process couldn't be
allowed to affect that. I had thought that i would call the logger and
let it run in it's own thread, allowing execution to continue in the
main application. I will probably use a database based error log in
future if I got this to work.

I like the Local thread storage technique, I knew there had to be a
better way to avoid each variable being overwritten by other thread
calls.

Anyway, I agree that using a queue to log messages would be a much more
efficient solution, as there may be many attempts to log messages
within the 500msec window.

I presume then that I would call this logger at the beginning of the
process and it would be constantly running but as a separate thread,
reading from the queue and writing to a file? I can pass a user defined
type to a queue? Would it be best to stop the logger thread when the
queue is empty and call it again when I add to the queue (if there is
not a thread running already)?

Thanks for your help,

Colly

Mar 29 '06 #3
CollyMitch wrote:
Brian,

Firstly thank-you for your feedback.

I get the message when it tries to compile.

It sounds like a syntax error to me. Fortunately, if you look hard
enough you'll eventually find it.
The reason I had used a threaded solution was because the process could
only take a maximum of 500msec and a slow logging process couldn't be
allowed to affect that. I had thought that i would call the logger and
let it run in it's own thread, allowing execution to continue in the
main application. I will probably use a database based error log in
future if I got this to work.

I like the Local thread storage technique, I knew there had to be a
better way to avoid each variable being overwritten by other thread
calls.

I don't think you need TLS for your particular situation. It's rarely
used anyway.
Anyway, I agree that using a queue to log messages would be a much more
efficient solution, as there may be many attempts to log messages
within the 500msec window.

Yes. A single worker thread approach is definitely the way to go here.
I presume then that I would call this logger at the beginning of the
process and it would be constantly running but as a separate thread,
reading from the queue and writing to a file? I can pass a user defined
type to a queue? Would it be best to stop the logger thread when the
queue is empty and call it again when I add to the queue (if there is
not a thread running already)?
You can either start the logger at the beginning of the process or you
could use a lazy initialization technique. It doesn't really matter.
Yes, the logger thread, once started, would run all the time. I
wouldn't stop it when the queue empties because in most cases the queue
would empty before the next log message was queued. Here's some code
to get you started. My VB is a little rusty since I'm a C# guy.

Public Class Logger

' You'll need to write your own BlockingQueue class.
Private m_Queue As BlockingQueue = New BlockingQueue
Private m_Thread As Thread = Nothing

Public Sub Logger()

m_Thread = New Thread(AddressOf LoggerThread)
m_Thread.IsBackground = True
m_Thread.Start()

End Sub

Public Sub WriteToLog(ByVal message As String)

' Put the message in the queue. This will wake the logger thread.
m_Queue.Enqueue(message)

End Sub

Private Sub LoggerThread()

Do While True

' The line will block until an item appears in the queue.
Dim message As String = DirectCast(m_Queue.DequeueWait(), String)

WriteMessageToFile(message)

Loop

End Sub

End Class

The only thing I haven't provided you is the BlockingQueue. The
blocking queue would implement the standard producer-consumer pattern
and provide a DequeueWait method that blocks if the queue is empty. I
posted an example implementation in C# at...

<http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=BD9982D6-B14D-402B-B855-5D74D61ABC94>

Brian

Thanks for your help,

Colly


Mar 29 '06 #4
Brian,

That's great thanks. I was going to ask how will I be able to add to
the queue when the thread is removing from the queue at the same time.
I would use the SyncLock method to lock the queue when adding and
removing elements? The wait handle you use - this waits until the queue
is unlocked and then adds/dequeues, this would mean that as soon as the
queue was read the wait handle is reset to allow adding?

'Lock the queue
SyncLock myQueue.SyncRoot
msg = myQueue.Dequeue
End SyncLock 'now unlocked
WriteMessageToFile(msg)

This locks the queue before Dequeuing > what happens when I try to add
an element to the queue - i would need to use the same synclock. You
use a wait handle to wait for it to be unlocked?
_WaitHandle.WaitOne();


Thanks again for your help,

Colly

Mar 29 '06 #5

CollyMitch wrote:
Brian,

That's great thanks. I was going to ask how will I be able to add to
the queue when the thread is removing from the queue at the same time.
I would use the SyncLock method to lock the queue when adding and
removing elements? The wait handle you use - this waits until the queue
is unlocked and then adds/dequeues, this would mean that as soon as the
queue was read the wait handle is reset to allow adding?
The WaitHandle is used to make the Dequeue method block if nothing is
in the queue. The Enqueue method will signal the wait handle and the
Dequeue method will wake up and try to dequeue an item before another
thread does. If the queue is empty when the thread wakes (because
another thread woke first) then it will loop back around to the
WaitHandle.WaitOne() method again and sleep some more.

'Lock the queue
SyncLock myQueue.SyncRoot
msg = myQueue.Dequeue
End SyncLock 'now unlocked
WriteMessageToFile(msg)

You should make your queue class thread-safe. That way you won't need
to use SyncLock inside the Logger class. I recommend taking the
BlockingQueue class I have and just port it to VB. The synchronization
is a bit tricky and it would save you a lot of time.
This locks the queue before Dequeuing > what happens when I try to add
an element to the queue - i would need to use the same synclock. You
use a wait handle to wait for it to be unlocked?
_WaitHandle.WaitOne();

Again. The WaitHandle is used to make to the Dequeue method block if
nothing is in the queue. It has nothing to do with locking the queue.
That's what SyncLock (or lock in C#) do.

Thanks again for your help,

Colly


Mar 29 '06 #6
Brian,

I've got it working really well, really fast and it works in perfect
sequence. I've used a synchronised queue and the AutoResetEvent. I
didn't port you blocking class but did learn a lot from it.

I've declared the thread as a background thread, if I didn't do this -
would it continue to run in the infinite loop even when the calling
application ended?

Thanks again for your all help,

Colly

Mar 30 '06 #7

CollyMitch wrote:
Brian,

I've got it working really well, really fast and it works in perfect
sequence. I've used a synchronised queue and the AutoResetEvent. I
didn't port you blocking class but did learn a lot from it.

AutoResetEvent is fine. Though, the semantics of the queue may be
slightly different than my approach which used ManualResetEvent. An
even better approach is to use Monitor.PulseAll and Monitor.Wait. The
following article demonstrates how this is done.

<http://www.yoda.arachsys.com/csharp/threads/deadlocks.shtml>
I've declared the thread as a background thread, if I didn't do this -
would it continue to run in the infinite loop even when the calling
application ended?


Yep. That's pretty much right. If you want to shutdown the thread
gracefully you'll have to modify the Logger class a bit. Maybe
something like the following.

Public Class Logger

' You'll need to write your own BlockingQueue class.
Private m_Queue As BlockingQueue = New BlockingQueue
Private m_Thread As Thread = Nothing
Private m_Shutdown as ManualResetEvent = New ManualResetEvent(False)

Public Sub Logger()

m_Thread = New Thread(AddressOf LoggerThread)
m_Thread.IsBackground = True
m_Thread.Start()

End Sub

Public Sub Stop()

m_Shutdown.Set()
m_Thread.Join()

End Sub

Public Sub WriteToLog(ByVal message As String)

' Put the message in the queue. This will wake the logger thread.
m_Queue.Enqueue(message)

End Sub

Private Sub LoggerThread()

Dim keepGoing As Boolean = True

Do While keepGoing

Dim handles(2) as WaitHandle
handles(0) = m_Shutdown
handles(1) = m_Queue.WaitHandle

Dim index as Integer = WaitHandle.WaitAny(handles)

If index = 0 Then

keepGoing = False

Else

Dim message As String = DirectCast(m_Queue.Dequeue(), String)

WriteMessageToFile(message)

End If

Loop

End Sub

End Class

Mar 30 '06 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Ganbold | last post by:
Hi, I'm new to multi-threaded programming and reading the book "Programming with POSIX Threads" and trying to understand concepts and coding. What I'm trying to do is to rewrite mysql client...
6
by: ben | last post by:
I am needing a web service to be single threaded. Is this possible? Any ideas would be helpful
3
by: Rsrany | last post by:
I've been working on a few gtk applications and need to tie a hot key catcher into a thread. I am currently finding threaded user32.GetMessageA do not work. I have included two programs: 1) a...
14
by: Snor | last post by:
I'm attempting to create a lobby & game server for a multiplayer game, and have hit a problem early on with the server design. I am stuck between using a threaded server, and using an event driven...
14
by: =?ISO-8859-1?Q?Tom=E1s_=D3_h=C9ilidhe?= | last post by:
As far as I know, the C Standard has no mention of multi-threaded programming; it has no mention of how to achieve multi-threaded programming, nor does it mention whether the language or its...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.