|
I said I didn't think it'd be too hard to sync the IsBusy etc. I hate saying that without knowing for sure so I've knocked up a quick version. This should be OK (untested!), but if using other locks or other synchronisation methods in your other code I'd use the MS one. (Needs comments and descriptions adding)
using System;
using System.ComponentModel;
using System.Threading;
namespace DaveyM69.ComponentModel
{
[DefaultEvent("DoWork")]
[DefaultProperty("WorkerReportsProgress")]
public class SaferBackgroundWorker : Component
{
public event DoWorkEventHandler DoWork;
public event ProgressChangedEventHandler ProgressChanged;
public event RunWorkerCompletedEventHandler RunWorkerCompleted;
private bool cancellationPending;
private bool isBusy;
private AsyncOperation operation;
private SendOrPostCallback operationCompleted;
private SendOrPostCallback progressReporter;
private object syncLock = new object();
private bool workerReportsProgress;
private bool workerSupportsCancellation;
private ParameterizedThreadStart workerThreadStart;
public SaferBackgroundWorker()
{
cancellationPending = false;
isBusy = false;
operation = null;
operationCompleted = new SendOrPostCallback(OperationCompleted);
progressReporter = new SendOrPostCallback(ProgressReporter);
workerReportsProgress = false;
workerSupportsCancellation = false;
workerThreadStart = new ParameterizedThreadStart(WorkerThreadStart);
}
[Browsable(false)]
public bool CancellationPending
{
get { lock (syncLock) { return cancellationPending; } }
}
[Browsable(false)]
public bool IsBusy
{
get { lock (syncLock) { return isBusy; } }
}
[DefaultValue(false)]
public bool WorkerReportsProgress
{
get { lock (syncLock) { return workerReportsProgress; } }
set { lock (syncLock) { workerReportsProgress = value; } }
}
[DefaultValue(false)]
public bool WorkerSupportsCancellation
{
get { lock (syncLock) { return workerSupportsCancellation; } }
set { lock (syncLock) { workerSupportsCancellation = value; } }
}
public void CancelAsync()
{
if (!WorkerSupportsCancellation)
throw new InvalidOperationException("Worker doesn't support cancellation");
SetCancellationPending(true);
}
protected virtual void OnDoWork(DoWorkEventArgs e)
{
DoWorkEventHandler eh = DoWork;
if (eh != null)
eh(this, e);
}
protected virtual void OnProgressChanged(ProgressChangedEventArgs e)
{
ProgressChangedEventHandler eh = ProgressChanged;
if (eh != null)
eh(this, e);
}
protected virtual void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
{
RunWorkerCompletedEventHandler eh = RunWorkerCompleted;
if (eh != null)
eh(this, e);
}
private void OperationCompleted(object state)
{
SetIsBusy(false);
SetCancellationPending(false);
OnRunWorkerCompleted((RunWorkerCompletedEventArgs)state);
}
private void ProgressReporter(object state)
{
OnProgressChanged((ProgressChangedEventArgs)state);
}
public void ReportProgress(int percentProgress)
{
ReportProgress(percentProgress, null);
}
public void ReportProgress(int percentProgress, object userState)
{
if (!WorkerReportsProgress)
throw new InvalidOperationException("Worker doesn't report progress");
ProgressChangedEventArgs arg = new ProgressChangedEventArgs(percentProgress, userState);
if (operation == null)
progressReporter(arg);
else
operation.Post(progressReporter, arg);
}
public void RunWorkerAsync()
{
RunWorkerAsync(null);
}
public void RunWorkerAsync(object argument)
{
if (IsBusy)
throw new InvalidOperationException("Worker is busy");
SetIsBusy(true);
SetCancellationPending(false);
operation = AsyncOperationManager.CreateOperation(null);
workerThreadStart.BeginInvoke(argument, null, null);
}
private void SetCancellationPending(bool value)
{
lock (syncLock) { cancellationPending = value; }
}
private void SetIsBusy(bool value)
{
lock (syncLock) { isBusy = value; }
}
private void WorkerThreadStart(object obj)
{
object result = null;
Exception error = null;
bool cancelled = false;
try
{
DoWorkEventArgs doWorkArgs = new DoWorkEventArgs(obj);
OnDoWork(doWorkArgs);
if (doWorkArgs.Cancel)
cancelled = true;
else
result = doWorkArgs.Result;
}
catch (Exception exception)
{
error = exception;
}
RunWorkerCompletedEventArgs e = new RunWorkerCompletedEventArgs(result, error, cancelled);
operation.PostOperationCompleted(operationCompleted, e);
}
}
}
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
Hi,
I'm not sure what it is you are trying, but it sure sounds like you are having synchronization problems.
Some comments:
1.
As usual, MSDN says: "Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe."
So if you have several threads interested in a single BGW, you'll need some synchronization.
2.
the GUI magic of a BGW (i.e. accessing the GUI safely from within the ProgressChanged or RunWorkerCompleted events) only works if the BGW got created by the main thread.
3.
as (almost) all event handlers, the first parameter in ProgressChanged or RunWorkerCompleted identifies the BGW itself. So it should be rather easy to share a Progress or Completed handler amongst multiple BGWs.
4.
if you want to pass several jobs to the same BGW, to be executed in sequence, why not use a queue (with a lock!), and have DoWork fetch its jobs from that queue?
5.
which timer class are you using? only System.Windows.Forms.Timer ticks on the main thread; the others tend to tick on a ThreadPool thread.
6.
Windows timers have limited resolution; you mentioned 10msec and shorter; not sure you are getting those. Have a read of this: Timer surprises, and how to avoid them[^]
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
There is windows service application that should access some network resource and get data from it (e.g. SQL server, network server with some files, etc...)
There might be N such threads running in parallel each connecting to its own resource. Thus there are N instances of the helper class (performing such remote data collection) in the List array in the instance field of the service.
4. They need to run in parallel not in sequence one after another.
5. Timer is System.Threading.Timer. I'm using logging with milliseconds marks and can confirm accuracy depending on cpu load.
That is the timer tick function:
for (int i = 0; i < this.drives.Count; i++)
{
if (this.drvBackgroundWorkers[i].IsBusy == false)
{
BackgroundWorkerArgument argument = new BackgroundWorkerArgument()
{
threadId = i,
drive = this.drives[i]
};
this.drvBackgroundWorkers[i].RunWorkerAsync(argument);
}
}
drvBackgroundWorkers is not accessed in any thread code only in that tick function.
I wonder the reason for a failure??
Чесноков
|
|
|
|
|
1.
first of all, when a System.Threading.Timer ticks, its handler runs on an arbitrary ThreadPool thread, not on the thread that did start your BGW, and not on the thread that may be executing the current job of your BGW. And the BGW itself needs to access IsBusy() too. So there are several threads involved in accessing the one property.
2.
timer handler executions may overlap, i.e. a second one could start before the first one has finished. Here is proof, run it in debug mode and watch the times, and the counts:
System.Threading.Timer timer;
int count;
public override void Test(int arg) {
timer=new System.Threading.Timer(new TimerCallback(ticker), null, 30, 30);
}
protected void output(string s) {
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff ")+s);
}
public void ticker(object dummy) {
output("ticker("+count+") start");
for (int i=0; i<10000000; i++) { }
output("ticker("+count+") stop");
count++;
if (count>10) {
timer.Change(Timeout.Infinite, Timeout.Infinite);
output("done");
}
}
[ADDED]
I only tested on a dual-core, however I don't think it needs a multi-core for overlaps to occur.
[/ADDED]
One way to fix it, would be to make the timer single-shot; and fire it again (using Change) when its handler is done.
3.
you are trying to feed new jobs to existing BGW. The easy way out would be to create a new BGW each time; yes, that is more expensive.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
modified on Sunday, May 23, 2010 11:18 AM
|
|
|
|
|
Hi all,
I have a DataGridView where the user can change the columns widths (by dragging the column header divider). However, I'd like to disable the functionality that double-clicking the column header divider auto-resizes the column with. I tried using the ColumnDividerDoubleClick event to handle this event manually, but the column width still automatically resizes.
Ideas?
Thanks!
Eyal.
|
|
|
|
|
|
It is a Sunday, so most of Europe is not at work.
It is also sunny and hot in the UK, so most people are out in the fresh air, warming and drying out after a long cold winter. Some are trying to work out what that big, hot, yellow thing up there is, since we haven't seen it for a couple of years...
Normal service will resume tomorrow. Probably.
If the warm weather doesn't encourage too much beer drinking, with resulting spontaneous-Monday-morning-illness problems. It might.
Did you know:
That by counting the rings on a tree trunk, you can tell how many other trees it has slept with.
|
|
|
|
|
Hello did you found any answer for this?
Thanks.
|
|
|
|
|
Hi
I'm new in C#.net. I have been facing a problem for so many days but couldn't solve it yet.
Can anybody help me how can server get the ip address of connected client in c#?
i am using following code:
Socket rsock = m_workerSocket[m_clientCount];
textBox2.Text =
((IPEndPoint)rsock.RemoteEndPoint).Address.ToString();
but instead of getting client address i always get server ip address.
can anybody help me to sort out this problem?
|
|
|
|
|
Try IpEndPoint ipend = rsock.Client.RemoteEndPoint; .
My signature "sucks" today
|
|
|
|
|
hi
thanxs fo ur rply
but Im facing the same problem with this code.
now what shud i do?
thanx
|
|
|
|
|
Please read How to get an answer to your question[^]
Plz help me is not an appropriate subject. You have not formatted the code posted. If you want serious responses, then follow these guidelines.
I know the language. I've read a book. - _Madmatt
|
|
|
|
|
hi
thanx 4 ur guidance.i want to get ip address of client on server side but remote end property does not work in this context.
thanx.
|
|
|
|
|
I have program develop using C# 2008 with access database 2003. How to include this database in installer?..I build Installer Using Publish..
|
|
|
|
|
joynil wrote: I build Installer Using Publish
I haven't done that.
I always create an installer project. With an installer project...
0) Right-click the installer project
1) Click View | File system
2) Right-click the left panel
3) Click Add special folder | User's application data folder
(or Common files folder if you prefer)
4) Right-click the right panel
5) Click Add | File
6) Add the database file
|
|
|
|
|
hi
my Code IS:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace RaceCondition
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string s=" ";
Thread t1, t2;
private void button1_Click(object sender, EventArgs e)
{
t1 = new Thread(f1);
t2 = new Thread(f2);
t1.Start();
t2.Start();
while (t1.IsAlive||t2.IsAlive)
{
Thread.Sleep(50);
}
for (int i = 0; i < s.Length; i++)
{
if (s[i]=='n')
{
listBox1.Items.Add("");
}
else
{
listBox1.Items[listBox1.Items.Count-1]+=s[i].ToString();
}
}
}
Random r = new Random();
void f1()
{
Thread.Sleep(r.Next(2));
System.Threading.Monitor.Enter(s);
for (int i = 1; i <= 100; i+=2)
{
Thread.Sleep(r.Next(2));
s += 'n';
Thread.Sleep(r.Next(2));
s += "T1 ";
Thread.Sleep(r.Next(2));
s += i.ToString() + " ";
Thread.Sleep(r.Next(2));
s += i.ToString() + " ";
Thread.Sleep(r.Next(2));
s += i.ToString() + " ";
Thread.Sleep(r.Next(2));
System.Threading.Monitor.Exit(s);
}
Thread.Sleep(r.Next(2));
}
void f2()
{
Thread.Sleep(r.Next(2));
System.Threading.Monitor.Enter(s);
for (int i = 2; i <= 100; i += 2)
{
Thread.Sleep(r.Next(2));
s += 'n';
Thread.Sleep(r.Next(2));
s += "T2 ";
Thread.Sleep(r.Next(2));
s += i.ToString() + " ";
Thread.Sleep(r.Next(2));
s += i.ToString() + " ";
Thread.Sleep(r.Next(2));
s += i.ToString() + " ";
Thread.Sleep(r.Next(2));
System.Threading.Monitor.Exit(s);
}
Thread.Sleep(r.Next(2));
}
}
}
WHat is the problem of this code
I want to use Monitor TO Reslove Race Condition
|
|
|
|
|
Hi,
I haven't studied that in any detail, I do have a few comments though:
1.
you have a Monitor.Exit inside a for loop, whereas the Monitor.Enter is executed only once? That means most of the loop is not protected by the monitor.
2.
Thread.Sleep() takes an integer parameter representing the requested delay in milliseconds. However, its resolution is really system-dependent, and never that good. It typically will round up to a multiple of some 15 milliseconds. If you want details, I suggest you read Timer surprises, and how to avoid them[^].
3.
Rather than constructing a poll loop to wait for the end of one or more threads, I suggest you read up on Thread.Join()
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
I'm sure to some of you, this is pretty simple, and I think I know what it does, but I haven't been able to find the answer on the net.
What exactly do the '?' and ':' mean in this bit of code?
(dssubcat.Tables[0].Rows[0]["gallery_img"]) == System.DBNull.Value ? "" : dssubcat.Tables[0].Rows[0]["gallery_img"])
Does that line say that if that item in the DataSet is equal to the DBNull value, then return "" and if it doesn't return the item?
modified on Saturday, May 22, 2010 5:30 PM
|
|
|
|
|
This is known as the ternary operator, and you are right about what your assumption of the logic here is. Basically, it follows the pattern:
(some boolean test) ? (part that gets executed if true) : (part that gets executed if false). It's very easy to get carried away with this operator and produce some code that looks like this:
value < lowerBounds ? value > 0 ? Console.WriteLine("We have a problem") : Console.WriteLine("Value less than or equal to zero") : Console.WriteLine("The value is OK"); If you must use it, use it with care; at some point you may be responsible for trying to figure out what you were smoking when you wrote the code.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
Honestly, I'm never that concerned with lessening the number of lines or getting rid of a few extra key strokes that I would probably ever use it. I just saw it in a question and wanted to make sure I understood for sure what it was.
Thanks!
|
|
|
|
|
You are welcome, and you are right that saving key strokes is no excuse.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
I use this construct a lot, but never nest them - that's where you get into maintenance trouble down the road.
I've seen code that had these nested as many as FIVE deep! MY EYES!
.45 ACP - because shooting twice is just silly ----- "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "The staggering layers of obscenity in your statement make it a work of art on so many levels." - J. Jystad, 2001
|
|
|
|
|
Hi,
You already have your answer so I won't expand on that but I thought this may be worth mentioning.
I don't often use them because of readability issues they create. They are very useful however where it is not possible to use an if/else block such as when constructor chaining. For example, these are the constructors for an ImapClient class that I'm working on - the 3rd constructor needs to assign a port depending on the value of another parameter. I could put an if/else block inside the constructor itself but then I lose the benifit of only having code in one place that all other constructors call into. Using ?: solves this.
public const int DefaultPort = 143;
public const int DefaultPortSsl = 993;
public static readonly ImapSecurity DefaultSecurity = ImapSecurity.Tls;
private string hostname;
private int port;
private ImapSecurity security;
public ImapClient(string hostname)
: this(hostname, DefaultPort, DefaultSecurity)
{ }
public ImapClient(string hostname, int port)
: this(hostname, port, DefaultSecurity)
{ }
public ImapClient(string hostname, ImapSecurity security)
: this(hostname, security == ImapSecurity.Ssl ? DefaultPortSsl : DefaultPort, security)
{ }
public ImapClient(string hostname, int port, ImapSecurity security)
{
this.hostname = hostname;
this.port = port;
this.security = security;
}
public enum ImapSecurity
{
None,
Tls,
Ssl,
}
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
I have same problem with dll(Delphi):
function _SignString(hProv: HCRYPTPROV; InputStr: PByte;
InputStrLen: DWORD; var ResultStr: PByte;
var ResultStrLen: DWORD): Boolean; stdcall;
[DllImport("sspCrypto.dll", EntryPoint = "_SignString")]
public static extern bool SignString(
IntPtr hProv,
IntPtr InputStr,
uint InputStrLen,
[Out]out IntPtr ResultStr,
[Out]out uint ResultStrLen);
function return true, but ResultStr has no correct importance
|
|
|
|
|
I've never used Delphi, so I'm not sure how to read that exactly. There are basically two possibilities:
1. most likely
if the Delphi code is supposed to allocate and fill native memory with a result string, then what you are getting is really a pointer into the native world, and you must use one of the Marshal.PtrToStringXYZ() methods to get the corresponding managed string.
2. alternatively
if the Delphi code needs a pointer to an existing buffer it is supposed to fill, then you should replace the last but one parameter in the prototype and in the call by a StringBuilder instance, which must have been created (with new) and given sufficient capacity (the parameter in its constructor).
[ADDED]
If the native function wants stdcall, your prototype should say so, using CallingConvention=CallingConvention.StdCall within the parentheses of the DllImport attribute.
[/ADDED]
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
modified on Saturday, May 22, 2010 6:04 PM
|
|
|
|
|