|
In this case, the actual copy operation would be on a background thread. It would have to notify a component on the UI thread, probably through an event or callback delegate, that this condition exists.
|
|
|
|
|
Yeap, actually I am doing the copy operation in RunsOnThread()
The method ShowProgress internally uses BeginInvoke and InvokeRequired to access the components in the GUI about the progress of the copy file.
e.g. ------------------------------------------------------------------
public void ShowProgress(string msg, int percentDone)
{
if (InvokeRequired)
{
System.EventArgs e = new MyProgressEvents(msg, percentDone);
object[] pList = { this, e };
BeginInvoke(new MyProgressEventsHandler(UpdateProgressBar), pList);
}
else
{
UpdateProgressBar(this, new MyProgressEvents(msg, percentDone));
}
}
private delegate void MyProgressEventsHandler(object sender, MyProgressEvents e);
private void UpdateProgressBar(object sender, MyProgressEvents e)
{
FrmSentPrtPgres.label_MsgContext.Text = e.msg;
FrmSentPrtPgres.progressBar.Value = e.percentDone;
}
-------------------------------------------------------------------------------------
|
|
|
|
|
I have been chasing this bug for three days now and wondered if anybody out there could point me in the right direction.
I have a circular array generated from a structure. We are writing data to this array and found that the second write was overwriting part of the first record. To simplify debugging we have put some test code that changes what is to be written and then does a second write. Here is the code:
class CAN
{
public struct CANTXSTRUCT
{
public int PGN;
public byte DLC;
public byte[] TxData;
}
private const int CANArraySize = 20;
static private int CANFront = 1;
static private int CANRear = 0;
static private CANTXSTRUCT[] arCANTx = new CANTXSTRUCT[CANArraySize + 1];
static public void QueueCANTxMsg(int PGN, byte DLC, byte[]TxData)
{
if ((CANRear + 2) % CANArraySize == CANFront)
{
MessageBox.Show("CAN Tx Array Overflow, Press OK to continue",
"Error Warning", MessageBoxButtons.OK);
return;
}
CANRear = (CANRear + 1) % CANArraySize;
CAN.arCANTx[CANRear].PGN = PGN;
CAN.arCANTx[CANRear].DLC = DLC;
CAN.arCANTx[CANRear].TxData = TxData;
TxData[0] = 0xFF;
CANRear = (CANRear + 1) % CANArraySize;
CAN.arCANTx[CANRear].PGN = PGN;
CAN.arCANTx[CANRear].DLC = DLC;
CAN.arCANTx[CANRear].TxData = TxData;
}
When the failing line is executed it overwrites the first written CAN.arCANTx[CANRear].TxData value. The CANRear value appears to beworking correctly and I think the problem is associated with the byte array copy implicit in the failing line.
Can anyone see what I am doing wrong? Cheers Bruce
|
|
|
|
|
Hi Bruce,
having fun with a CAN bus? been there using C, not C#.
Here are some remarks:
0. Not sure why you have one extra element in the CANTXSTRUCT array.
1. I am not sure why you want to store a message twice. Seems very odd.
2. your QueueCANTxMsg() method is queueing two messages, however they share all the data, which is fine for value types (PGN, DLC) but not for reference types: the TxData you are storing twice is the same array twice, so changing a byte in it (TxData[0] = 0xFF; ) will reflect in both copies, since you only are storing a reference.
3. your overflow test is not correct, if (CANRear + 1) % CANArraySize == CANFront you are also overflowing the circular buffer (adding two can make you look OVER the front node).
4. if you plan on using QueueCANTxMsg() from more than one thread (say a regular thread and some asynchronous datareceived handler) then you should lock otherwise the pointer adjustment (CANRear = (CANRear + 1) % CANArraySize; ) could be interrupted resulting in using the same location twice.
|
|
|
|
|
Hi Luc,
The circular array handling in point 0 and 3 is an old standard technique I have used for years that runs great but requires an unused buffer address.
The second message in the code sample was just test code so I could see the problem without leaving the function.
Point 4 - Only ever calling from 1 thread but your suggestion is well taken.
I am sure you are on the right lines with point 2 but how do I change this to store real individual values in a real circular array?
Thanks for your input. After 3 days it sure is appreciated.
Cheers, Bruce
|
|
|
|
|
Hi Bruce,
Bruce Coward wrote: an unused buffer address
I agree a simple circular buffer wastes one slot, since you must discriminate the empty case (getptr=putptr) and the full case (getptr=putptr), which is easiest by never filling the buffer completely, so there will always be an empty slot, however it moves around: the pointer arithmetic should use the actual array size, whatever extra elements get allocated are simply wasted.
So if you do array[DIM+1} then you should also do PTR=(PTR+1)%(DIM+1) otherwise PTR will never point to ARRAY[DIM].
Bruce Coward wrote: how do I change this to store real individual values
You must make sure the data either resides in a different array each time (so the caller must provide a new array each time), or you must copy the data into an array you allocate yourself. I prefer the latter, and I would try and allocate all the buffers just once (when intializing the circular buffer) and copy the data in them.
Depending on how you actually obtain the data from CAN, there is or isn't a way of saving one copy operation:
- split the queueMessage method in two parts;
- use first part to obtain the next array (the array preallocated for the next slot in the circular buffer) but don't advance the put pointer
- call "driver" to fill that buffer
- call remaining part of queueMessage to stuff value types, and advance slot pointer which makes it readable for the CAN message consumer.
|
|
|
|
|
The line you pointed out does not copy the array. Array assignments never perform an implicit copy, even in structures. As a side note, if you could do sizeof(CANTXSTRUCT), it would be the same regardless of the size of TxData because the structure only holds a reference to the array not the actual bytes.
The problem is that you are assigning CAN.arCANTx[CANRear].TxData variable to hold a reference to the parameter TxData. If you check the value after the first line of "Test Code", you should be seeing overwrite because doing (parameter)TxData[4] = 0x87 is equivalent to CAN.arCANTx[CANRear].TxData[4] = 0x87 since both arrays reference the same bytes. If you want to copy the data, you will need to create a new array to assign to the structure and call Array.Copy yourself.
Also, I would suggest using the Queue<t> class instead of making your own circular array.
|
|
|
|
|
Gideon Engelberth wrote: I would suggest using the Queue class instead of making your own circular array.
I beg to differ. There may be very good reasons to have a pre-allocated data structure to handle all traffic, since it avoids a lot of object creation and destruction, and it provides an upper bound to the amount of data that can be stored.
In fact I did some similar CAN drivers before, on embedded systems which did not have really dynamic memory, but even if they had I probably would have gone with the circular buffer anyway. BTW: when designed carefully one can forego all locking, which is quite useful when part of the code runs in an interrupt service routine.
|
|
|
|
|
Hi Bruce,
I find a circular buffer much easier to understand and manage with a control variable storing the current data amount. With this additional piece of information in place the buffer full/empty state is obvious and the empty slot can be discarded.
Not tested but something like this:
class CAN {
public struct CANTXSTRUCT {
public int PGN;
public byte DLC;
public byte[] TxData;
}
private const int CANArraySize = 20;
static private int CANFront = 0;
static private int CANRear = 0;
static private int currentCount = 0;
static private CANTXSTRUCT[] arCANTx = new CANTXSTRUCT[CANArraySize];
static public void QueueCANTxMsg(int PGN, byte DLC, byte[] TxData) {
if (currentCount < arCANTx.Length) {
CANRear = (CANRear + 1) % arCANTx.Length;
currentCount++;
} else {
}
}
static public void RemoveMsg() {
if (currentCount > 0) {
CANFront = (CANFront + 1) % arCANTx.Length;
currentCount--;
} else {
}
}
}
Alan.
|
|
|
|
|
Hi Alan,
while I agree on two pointers plus amount being easier to understand, the nice thing about a circular buffer with only two pointers (and an empty slot) is that you don't need to lock if there is only one producer and one consumer: each pointer will have one writer and two readers, so when writing is atomic all is fine (when implemented carefully that is). Adding a currentCount makes the state redundant and prohibits atomic operations.
Remember, in a typical application, the consumer would be the app itself, the producer of incoming messages would be the CAN driver, which operates from an interrupt service routine (an asynchronous handler in .NET speak).
|
|
|
|
|
OnActivated()
MethodInvoker one function to initialize the data of the main form. And before beginInvoke, new the progress form B, the Form B to show the progress to the User. And there is a Timer in the form B, if the time is bigger than 2 seconds, the B Form will showdialog itself to forbide user operation. and then if MethodInvoke function finishs the task, it will stop the form B.
then the error shows. "Cross-thread access Form B from the thread is not the thread created by it."
the MethodInvoker is the another thread?
|
|
|
|
|
You can only change or interact with the user interface on the user interface's thread. If you want to change an element of the UI from another thread you have to do something like use the Invoke method on the Control that you wish to manipulate.
|
|
|
|
|
You mean that:
After initialize data, create a method invoke for the Form B stop function to stop FormB. Right?
I am to know what will do in the invoke method?
|
|
|
|
|
Look up the InvokeRequired property on MSDN or Google. You will find lots of examples there, together with a full explanation of what's going on and why.
Henry Minute
Do not read medical books! You could die of a misprint. - Mark Twain
Girl: (staring) "Why do you need an icy cucumber?"
“I want to report a fraud. The government is lying to us all.”
|
|
|
|
|
All timers tick on a separate thread, except for Windows.Forms.Timer
|
|
|
|
|
Hi All,
I'm just writing some core 'primitives' in a class library for data processing purposes. These primitives are things like Names, Addresses, Telephone numbers etc ... standard user data stuff.
At present I've defined them as structs but I'm wondering if this is the most inexpensive way to structure them. The objects mostly consist of strings and maybe a couple of other structs. The issue is that we are going to be processing millions of these and in most cases some bits require transmission over Wcf. At some points the Master object will pass into a process via Wcf a subset of its data and then process the results back into itself.
My concern comes from the differences between holding these as value types and by doing so forcing the runtime to make copies of the actual data rather than references. Once some data hits a DataContract it's effectively going to be copied again, sent to the process, that process will send it back only to be copied again when the master object processes the results.
I feel like I should rewrite them as classes, any input would be appreciated.
Cheers,
|
|
|
|
|
If each one is only going to contain a few value types then use a struct. If it's going to contain a large amount or any reference types (a string is a reference type that behaves like a value type) then use a class.
If you decide to use a class and you know it's going to need to be copied, then it may be worth implementing Clone and if needed DeepClone methods to provide suitable copies.
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
DaveyM69 wrote: a string is a reference type that behaves like a value type
A string is simply immutable. Value types work best when they are immutable but they don't have to be.
|
|
|
|
|
Make them classes unless there's a good reason to make them structs.
Do you want the type to support null? -- Value types pretty much don't
Do you want to define operators for the type? -- I've found that operators make more sense on value types
Should the type be immutable? -- Value types generally tend toward immutability, but maybe that's due to operators
|
|
|
|
|
PIEBALDconsult wrote: Should the type be immutable? -- Value types generally tend toward immutability, but maybe that's due to operators
I would say the immutability aspect is fairly neutral. If it is mutable then I'd strongly recommend a class as value types are not good at mutability. But if it is immutable, could go either way for me - It wouldn't be a strong factor in making a choice.
|
|
|
|
|
hi everybody
I want to take my database backup which is created in sql server 2000 in windows application using C#
so i have no network its an independent system
i want to display all sqlserver instances in combobox
without internet(Lan etc..) how can i take backup my database using c#
hope you help me
thanks in advance
nagendra...
|
|
|
|
|
I don't know which bit you are needing help with. Listing the SQL Server instances or taking the backup.
You can use SMO (SQL Server Mangement Objects) to enumerate the available servers. http://msdn.microsoft.com/en-us/library/ms162169.aspx[^]
Since a SQL Backup can only be done to the machine that a SQL Server resides on a LAN isn't necessary. In fact, it won't make any difference since the backup file must be local to the SQL Server.
You can issue a backup command through the SqlCommand object in the .NET Framework and ExecuteNonQuery() .
|
|
|
|
|
I am having some issue handling an exception thrown in another thread in my UI. My question is how can I handle exceptions from another thread without syncronized the threads in the UI. I would prefer to sync the threads in the class where the method is called. Any suggestions?
Here is my code:
Localized fields
Test t = new Test();
Method that throws the exception
public class Test
{
public void DoSomething()
{
throw new MyCustomException(this,EventArgs.Empty);
}
}
The exception
public class MyCustomException : Exception
{
...
}
This is in the UI. Not multi-threaded
void CallException()
{
try
{
t.DoSomething();
}
catch(MyCustomException ex)
{
lblMessage.Text = "error";
}
}
This is also in the UI. Multi-threaded
void CallExceptionASync()
{
Thread thrd;
ThreadStart ts = (ThreadStart)delegate
{
t.DoSomething();
};
thrd = new Thread(ts);
thrd.Start();
}
|
|
|
|
|
I have created a workaround but I am not satisfied with it. If anyone has a better suggestion please let me know. Here is the workaround:
void CallExceptionASync()
{
Thread thrd;
ThreadStart ts = (ThreadStart)delegate
{
try
{
t.DoSomething();
}
catch(MyCustomException ex)
{
this.lblMessage.Invoke((MethodInvokder)delegate()
{
this.lblMessage.Text = ex.Message;
});
}
}
}
|
|
|
|
|
if the thread throws an exception, and the catch is to touch a GUI Control, then you need Control.Invoke, there is no way around that since that thread is not allowed to touch any Controls.
BTW: A BackgroundWorker has a Completed event which does the invoking automatically, and its event argument holds the exception that may have occurred.
|
|
|
|