|
It makes complete sense and is not convoluted at all. By the way, it's not VB doing it, it's Visual Studios debugger and YOU!
When you stop the app, the debugger stops all the threads in it, therefor modifying their state. But, it's not entirely stopped. When you get the value of a property, the debugger executes the property Get code, so the thread isn't entirely stopped.
As was already mentioned, the act of viewing an object changes it's state!
You're still doing a fair bit of bashing of VB.NET/.NET without trying to understand what's going on under the covers and why.
|
|
|
|
|
Sorry for the frustration showing.
But in an attempt to understand what is going on, here is the way threads should behave the way I understand it. Let's say I have two threads that calculate the results of some equations:
Thread-1 produces 1........2....... 4.......8........16.......32<br />
Thread-2 produces 1.5....1.837....2.49....3.929....7.789....21.737
1. All threads are suspended at time (t). Since Thread-1 is iterating faster than Thread-2, due to simpler equations, Thread-1 makes more progress than Thread-2, by time (t).
2. Since the exact moments that Threads 1 & 2 will be suspe nded will most likely occur asynchronously, this may add further uncertainty as to when Threads 1 & 2 will actually come to a halt. This could result in another complete iteration "slipping through" in either thread. But most likely, each thread will be suspended somewhere in the middle of an iteration. Nonetheless, the output values will not change until an iteration is completed.
3. At time (t + DELTAt), queries are made of the results from Threads 1 & 2. Obviously, both queries cannot be made at the exact same moment. So let's say that Thread-1 was queried first, followed by the query of Thread-2. The results are:
Thread-1.....16<br />
Thread-2.....2.49
4. The queries are NON-suspended actions performed on suspended Threads 1 & 2. Therefore, the results should be the same regardless of when the queries were actually made. Thus, the queries are actions that do not affect the results, once the threads have settled down into their suspended states.
There will be many times when the above timing disparities will not be an issue...I may simply need to see the results at time (t) regardless of any synchronization issues. If I need better synchronization so that the outputs are synchronized at some value of an independent variable, then I can simply stop each thread independently on separate time-dependent bounds.
Beyond that, why, in your understanding, would the queries affect the results?
|
|
|
|
|
First, a little about threading...
Threads are just units of work that are broken up to be run on a processor. There cannot be any more truly asynchronous threads running than there are physical processor cores.
The system has a scheduler which operates in a time cycle, lets call this cycle length "N". In N time, it has to execute all the threads that are available to be run (threads in other states are not scheduled). Each thread is given a time slice, "Y" in which to execute before the processor context switches to another thread. Any unused time is given to the system process which is just a simple loop (processors always have to be doing something). Unless a thread yields (Thread.Yield or Thread.Sleep), it will process for its entire Y period. Processes that do this are using the most processor resources and you can watch the task manager increase in percent usage when this happens.
So, getting back to your comments:
1) Suspending a thread is simply putting its state in the SleepWaitJoin.
2) The "exact" moment that the thread is (I believe) dependent on what the thread is currently doing. If the threads are in the scheduler but have not been run, then I think they are removed from the scheduler. If the thread is running then the scheduler has to wait until the time period expires or the thread yields to place it in the SleepWaitJoin state. So yes, another iteration can "slip" through while this process happens.
3) Queries happen at exactly the same moment according to the threads, this is because the thread executing the query is reading data in a thread that is suspended (one thread is running at a time). This doesn't mean however that you will get the results at the same time, again the thread could yield while reading data and you will get results at different thread times.
4) Again, the results may be different depending on how and when the scheduler interrupts the thread. Even your main thread is a thread, and its scheduled like all the rest of them.
What you are really trying to do is synchronize data between threads, (Thread 1 to main thread and Thread 2 to main thread). You should not rely on when a thread suspends to do this, you need to implement your own synchronization. Luckily there are things like Mutex's, AutoResetEvent, etc that you can use cross-thread to make one thread wait on your main thread to say "go ahead, continue".
|
|
|
|
|
Ron and everyone, thank you for your replies. I think the last post is pretty much what I am saying in my hypothetical example that Ron responded to. But in going back over what everyone has said, I still don't see how, once a thread is suspended and queried, that the result should differ afterwards when that very result is then stored in a string variable. The thread is suspended and is not processing any more of its operations.
"When you get the value of a property, the debugger executes the property Get code, so the thread isn't entirely stopped. As was already mentioned, the act of viewing an object changes it's state!"
If the Schrodinger's Cat analogy is used, it means that when a suspended thread is queried, it for some reason then processes at least some more lines of code OTHER THAN the Get property, that could change that value. Get should not be able to allow its thread to process any other code, like any equations that were about to be executed but were halted. But even then, only one query has been made. When afterwards, that result is stored in a string, it has already been "captured" and is simply sitting there, being copied over into the string. Immediately after the query, shouldn't interaction with that thread already have been finished? The query has been made, which means a result has been pulled OUT of the thread. So the result is now isolated from that thread. The thread is no longer involved and can't somwhow reach out of itself to change that returned value. So the string copy should match the query result, exactly. If what you suggest is true (and maybe it is ), that is analogous to taking a digital picture of someone with a camera, and then when you copied that image over to your harddrive, it changed into a picture of someone else!
|
|
|
|
|
I'm not going to get into this any further because you're beating a dead horse.
But, to add to the description that Ron just posted, in your description, you're ASSUMING that both of your background threads are running at the same time. This is NOT the case! Both threads, MAY be running, or one thread will run and the other won't be, or neither of them will be. Oh, and you're also assuming that threads will run in the order created. None of this is true. Threads can run in any order, for any amount of time, not necessarily the exact same size timeslice.
Normally, the only time you ever look at ThreadState is when you're waiting for it to spin up or waiting for it to end. That's it. Any other use is not reliable as a synchronization method.
|
|
|
|
|
Hi.
I have encountered a peculiar problem with modules that I have never seen before.
Here is a very simple example to demonstrate my point:
Module Module1
Dim x as integer = 1
End Module
Module Module2
Dim y as integer =2
End Module
Private Sub Form_Load(bla, bla, bla)
Me.Text = Str(x+y)
End Sub
When the program runs, both modules are automatically initialized so that the result is the value "3" getting sent to the form.
Up to now, I have never had a problem with modules not getting initialized. But in a new project I am working on, one gets initialized and the other does not. One of them simply does not get recognized. Adding Public to both/either does not help.
Does anyone have an idea as to the kinds of things that can cause this to happen?
Many thanks!
|
|
|
|
|
treddie wrote: But in a new project I am working on, one gets initialized and the other does not. Modules are initialized on first use, and the compiler has no incentive to change that behaviour. It should act as a static class does in C#.
treddie wrote: Does anyone have an idea as to the kinds of things that can cause this to happen? Check your usings; is there any "Module2" in the other namespaces? If there is, then it might be calling the wrong module.
Further, those x and y values should be prefixed with their module-name, to ensure that they're taken from that module (and not some other "global" function called "x").
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Eddy Vluggen wrote: Check your usings; is there any "Module2" in the other namespaces?
No, no others.
Eddy Vluggen wrote: Modules are initialized on first use, and the compiler has no incentive to change that behaviour.
OK, I think I see what you mean. The form_load procedure is referencing two variables with each declared in each module. Since they are both referenced in the form_load procedure, both modules initialize. But when I change the variable in module2 to "z" instead of "y", there is no reference for it in the form_load, so the compiler deems module2 uneccessary at the present time. At least a test of this confirms it in principle.
Eddy Vluggen wrote: those x and y values should be prefixed with their module-name
That part I knew about...I was just making a very simple demo which was not "safe".
|
|
|
|
|
hi all,
I have a code that get data from database into a datatable. My datatable is bind to datagridview without problem. I challenge is that i want user to perform some conditional formatting like alternate column color, automatically format this datatable adding image header, icon indicators (like what we have in excel). Then user will be allowed to export the datagridview to excel with all formats preserved.
Any help will be appreciated.
Tunde
Tunde
|
|
|
|
|
Member 4624169 wrote: Any help will be appreciated. There are some articles that show how to format a datagridview. There's probably also some articles on exporting to Excel. Most of them will focus on data - the DGV is exactly that - a gridview. Conditional formatting in a DGV will require code, where Excel will expect markup.
Member 4624169 wrote: Any help will be appreciated. Anything specific you want to know besides these general pointers?
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Hi, I need to be able to list all folder, sub folders and files for my application by using a ecurrsive loop how do I do this?
So far I have
Imports System.IO
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
Dim AppPath As String = Server.MapPath("~/")
ProcessDirectory(AppPath)
End If
End Sub
Protected Sub ProcessDirectory(ByVal DirPath As String)
Dim Dirs() As String = Directory.GetDirectories(DirPath)
For Each Dir As String In Dirs
Dim tvwRoot As TreeNode = New TreeNode()
If Dir.Substring(Dir.LastIndexOf("\") + 1) <> "App_Code" And Dir.Substring(Dir.LastIndexOf("\") + 1) <> "Bin" And Dir.Substring(Dir.LastIndexOf("\") + 1) <> "Files" Then
tvwRoot.Value = Dir.Substring(Dir.LastIndexOf("\") + 1).ToString
Dim Files() As String = Directory.GetFiles(Dir, "*.aspx")
For Each File As String In Files
Dim tnChild As TreeNode = New TreeNode()
tnChild.Value = File.Substring(File.LastIndexOf("\") + 1).ToString
tvwRoot.ChildNodes.Add(tnChild)
Next
TreeView1.Nodes.Add(tvwRoot)
Dim SubDirs() As String = Directory.GetDirectories(Dir)
For Each SubDir As String In SubDirs
Dim tvwSubFolder As TreeNode = New TreeNode()
tvwSubFolder.Value = SubDir.Substring(SubDir.LastIndexOf("\") + 1)
tvwRoot.ChildNodes.Add(tvwSubFolder)
Dim SubFiles() As String = Directory.GetFiles(Dir, "*.aspx")
For Each File As String In SubFiles
Dim tnChild As TreeNode = New TreeNode()
tnChild.Value = File.Substring(File.LastIndexOf("\") + 1).ToString
tvwSubFolder.ChildNodes.Add(tnChild)
Next
Next
End If
Next
End Sub
|
|
|
|
|
A WinForm-example, you'd have to translate it to a web-environment yourself;
Module Module1
Sub Main()
Using f As New Windows.Forms.Form()
Dim tv As New Windows.Forms.TreeView
tv.Dock = Windows.Forms.DockStyle.Fill
f.Controls.Add(tv)
Dim rootNode As Windows.Forms.TreeNode = tv.Nodes.Add("RootNode")
AddFolder("C:\inetpub\wwwroot", rootNode)
f.ShowDialog()
End Using
End Sub
Sub AddFolder(path As String, parent As Windows.Forms.TreeNode)
For Each folder As String In IO.Directory.GetDirectories(
path, "*.*", IO.SearchOption.TopDirectoryOnly)
Dim folderNode As Windows.Forms.TreeNode = parent.Nodes.Add(
folder, IO.Path.GetFileName(folder))
AddFolder(folder, folderNode)
Next
For Each file As String In IO.Directory.GetFiles(path, "*.*", IO.SearchOption.TopDirectoryOnly)
Dim folderNode As Windows.Forms.TreeNode = parent.Nodes.Add(file, IO.Path.GetFileName(file))
Next
End Sub
End Module
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
|
Uğur Şirin wrote: Can you help me example or source code? We can help with code if you are stuck or have questions. We do not write code on demand.
Uğur Şirin wrote: I need VB6 Script Codes, use to localhost XP. VB6 is deprecated; meaning that it's no longer supported.
"Good luck".
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
When a vb6 project is converted to vb.net using visual studio's conversion wizard, all forms and its controls have appearance in that of a vb6. How to change the appearance to vb.net style?
|
|
|
|
|
Rework the form by hand. There is no automated way to do it.
Frankly, you'll probably be rewriting the app from scratch to get all the benefits of .NET.
|
|
|
|
|
Hi.
I think an answer to this problem lies in the use of delegates and marshaling, but if so, I cannot figure this one out.
In vb6, you could use the AddressOf method to get the address of a function. vb.Net no longer allows such a simple idea. Some have even suggested that you do not need to get the address of a function. Apparently they do not use API functions, where getting the address of a function is essential.
Now, in vb.Net, if you attempt to use AddressOf(SomeFunction), as in:
lPrevWndProc = SetWindowLong(hControl, GWL_WNDPROC, AddressOf WindowProc)
You get the following error:
MSDN is as obtuse as ever when describing this problem where a simple example of how to replace the as-simple-as-it-gets vb6 "AddressOf" method with a vb.Net method would have been the obvious thing to do. I reference:
http://msdn.microsoft.com/en-us/library/ms184628%28v=vs.90%29.aspx[^]
which explains no more than the IDE message does in that respect, so they might as well have not even created that link. They offer other links to study which venture off into space because...All they needed to do was offer a simple comparison of how to do in vb.Net, to what was done in vb6.
I have searched high and low for an answer and all I have found is frustration.
Any help would be greatly appreciated. HELP! SOS!
|
|
|
|
|
There is an example here[^] in c#. Just run the code through an online coverter. You may need to touch up a few lines after converting.
|
|
|
|
|
Thanks for the link! I tried it and it does not work, yet. I am assuming that WindowProc is constantly listening for events, so that no button-click handler is required (which would defeat the purpose of using the API, anyway). But as it it is written now, I think it is deaf!
Public Class Form1
Public Delegate Function Win32WndProc(ByVal hWnd As IntPtr, _
ByVal Msg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Integer
Private Declare Function SetWindowLong Lib "user32" (ByVal hWnd As IntPtr, _
ByVal nIndex As Integer, _
ByVal newProc As Win32WndProc) _
As IntPtr
Private Declare Function CallWindowProc Lib "user32" (ByVal lpPrevWndFunc As IntPtr, _
ByVal hWnd As IntPtr, _
ByVal Msg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) _
As Integer
Private Const GWL_WNDPROC As Integer = -4
Private Const WM_LBUTTONDOWN As Integer = 513
Private oldWndProc As IntPtr = IntPtr.Zero
Private newWndProc As Win32WndProc = Nothing
Private Sub SubclassHWnd(ByVal hWnd As IntPtr)
newWndProc = New Win32WndProc(AddressOf MyWndProc)
oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, newWndProc)
End Sub
Private Function MyWndProc(ByVal hWnd As IntPtr, ByVal Msg As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) _
As Integer
Select Case (Msg)
Case WM_LBUTTONDOWN
MessageBox.Show("Clicked")
Return 0
End Select
Return CallWindowProc(oldWndProc, hWnd, Msg, wParam, lParam)
End Function
End Class
|
|
|
|
|
What is that you want to accomplish? The code I referenced will work, but is restricted to re-assigning windows owned by the process that invokes it. This is a restriction imposed by the SetWindowLong function (see: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx[^]; for the doc on GWL_WNDPROC).
Here is a version that works for a TextBox on the form.
Imports System.Runtime.InteropServices
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
SubclassHWnd(TextBox1.Handle)
End Sub
' Win32 API needed
<DllImport("user32")> _
Private Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal newProc As Win32WndProc) As IntPtr
End Function
<DllImport("user32")> _
Private Shared Function CallWindowProc(ByVal lpPrevWndFunc As IntPtr, ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
End Function
' A delegate that matches Win32 WNDPROC:
Private Delegate Function Win32WndProc(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
' from winuser.h:
Private Const GWL_WNDPROC As Integer = -4
Private Const WM_LBUTTONDOWN As Integer = &H201
' program variables
Private oldWndProc As IntPtr = IntPtr.Zero
Private newWndProc As Win32WndProc = Nothing
Private Sub SubclassHWnd(ByVal hWnd As IntPtr)
' hWnd is the window you want to subclass..., create a new
' delegate for the new wndproc
newWndProc = New Win32WndProc(AddressOf MyWndProc)
' subclass
oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, newWndProc)
End Sub
' this is the new wndproc, just show a messagebox on left button down:
Private Function MyWndProc(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Select Case Msg
Case WM_LBUTTONDOWN
MessageBox.Show("Clicked")
Return 0
Case Else
Exit Select
End Select
Return CallWindowProc(oldWndProc, hWnd, Msg, wParam, lParam)
End Function
'=======================================================
'Service provided by Telerik (www.telerik.com)
'Conversion powered by NRefactory.
'Twitter: @telerik, @toddanglin
'Facebook: facebook.com/telerik
'=======================================================
End Class This is pointless to do as there are other mechanisms to gain access to a textbox's WndProc method. The simplest would be to create custom textbox control and override it's WndProc method.
Public Class mtTB
Inherits TextBox
Private Const WM_LBUTTONDOWN As Integer = &H201
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
Select Case m.Msg
Case WM_LBUTTONDOWN
' do something
End Select
End Sub
End Class Or you could create a native window listener as shown here.[^]
|
|
|
|
|
Gawd I'm so stupid sometimes. I was driving home from the store today, and realized I hadn't started the listening process during form load. My version works now...You're version worked perfectly from the get-go.
But furthermore, to get mine to work, I had to change the function declarations to the "other" style.
From:
Private Declare Function SetWindowLong Lib "user32" (ByVal hWnd As IntPtr, _
ByVal nIndex As Integer, _
ByVal newProc As Win32WndProc) As IntPtr
Private Declare Function CallWindowProc Lib "user32" (ByVal lpPrevWndFunc As IntPtr, _
ByVal hWnd As IntPtr, _
ByVal Msg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Integer
To:
<DllImport("user32")> _
Private Shared Function SetWindowLong(ByVal hWnd As IntPtr, _
ByVal nIndex As Integer,
ByVal newProc As Win32WndProc) As IntPtr
End Function
<DllImport("user32")> _
Private Shared Function CallWindowProc(ByVal lpPrevWndFunc As IntPtr, _
ByVal hWnd As IntPtr, _
ByVal Msg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Integer
End Function
Why is one different than the other? I notice that the first is not shared and the second one is.
But I have never encountered any problems before using the first syntax.
modified 2-Jul-13 3:01am.
|
|
|
|
|
When using the "Declare" keyword, the default characterset modifier is ANSI.
From the documentation for Declare[^]
Quote:
Character Sets. You can specify in charsetmodifier how Visual Basic should marshal strings when it calls the external procedure. The Ansi modifier directs Visual Basic to marshal all strings to ANSI values, and the Unicode modifier directs it to marshal all strings to Unicode values. The Auto modifier directs Visual Basic to marshal strings according to .NET Framework rules based on the external reference name, or aliasname if specified. The default value is Ansi.
charsetmodifier also specifies how Visual Basic should look up the external procedure within its external file. Ansi and Unicode both direct Visual Basic to look it up without modifying its name during the search. Auto directs Visual Basic to determine the base character set of the run-time platform and possibly modify the external procedure name, as follows:
On an ANSI platform, such as Windows 95, Windows 98, or Windows Millennium Edition, first look up the external procedure with no name modification. If that fails, append "A" to the end of the external procedure name and look it up again.
On a Unicode platform, such as Windows NT, Windows 2000, or Windows XP, first look up the external procedure with no name modification. If that fails, append "W" to the end of the external procedure name and look it up again.
The error message you should have received was: Unable to find an entry point named 'SetWindowLong' in DLL 'user32.dll'. You could correct this like this:
Private Declare Auto Function SetWindowLong Lib "user32.dll" (ByVal hWnd As IntPtr, _
ByVal nIndex As Int16, _
ByVal newProc As Win32WndProc) As IntPtr
Private Declare Auto Function CallWindowProc Lib "user32" (ByVal lpPrevWndFunc As IntPtr, _
ByVal hWnd As IntPtr, _
ByVal Msg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Integer
|
|
|
|
|
Thanks for the clarification, TnTinMan. Much obliged. So much to learn...So little time!
|
|
|
|
|
|
Thank you, Bernhard!
I am testing it now.
|
|
|
|
|