Click here to Skip to main content
15,887,596 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hi,

In my application, I have used the backgroundworker thread for some background process. The thread called successfully and the Dowork event done all of his work. But, after completion of the Dowork event the RunWorkerCompleted event not getting fired. Any suggestion on this it would be great.

Here I have attached my sample code snippet.

What I have tried:

MainForm.cs:

public partial class MainForm : Form
 { 	
  
	public Form1()
	{
		InitializeComponent();
		
		InspectorWrapperThread wraperThread = new InspectorWrapperThread();
        wraperThread.Start();
	}
 }


InspectorWrapperThread.cs

public class InspectorWrapperThread : IDisposable
 {
 
	BackgroundWorker worker1;
	
	public InspectorWrapperThread()
	{

		worker1 = new BackgroundWorker();
		worker1.WorkerSupportsCancellation = true;
		worker1.DoWork += new DoWorkEventHandler(worker1_DoWork);
		worker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker1_RunWorkerCompleted);
	}
 
	 void worker1_DoWork(object sender, DoWorkEventArgs e)
	 {
		Called a function from here.
		function1(true);
		//Do some work here
	 }
	 
	 void worker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
	 {
		// This thread completion getting called correctly. 
	 }
	 
	 private void function1(bool exe)
	 {
		// do some operation and call the function like below.
		WorkerThread2 worker = new WorkerThread2();
		worker.function2();
	 }
 }

WorkerThread2.cs

public class WorkerThread2 : IDisposable
 {
	private BackgroundWorker backgroundWorkerThread2Tab;
	
	public WorkerThread2()
	{
		backgroundWorkerThread2Tab = new BackgroundWorker();
		backgroundWorkerThread2Tab.WorkerSupportsCancellation = true;
		backgroundWorkerThread2Tab.DoWork += new DoWorkEventHandler(backgroundWorkerThread2TabDoWork);
		backgroundWorkerThread2Tab.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerThread2TabRunWorkerCompleted);
	}
	
	public void function2()
	{
		// do some operation and call the function.
		
		HitAPIcalls();
	}
	
	private void HitAPIcalls()
	{
		// do some operation and call
		if (!backgroundWorkerThread2Tab.IsBusy)
                backgroundWorkerThread2Tab.RunWorkerAsync(mail);
	}
	
	void backgroundWorkerThread2TabDoWork(object sender, DoWorkEventArgs e)
	 {
		//This Dowork event getting called successfully and do all the operation without any issues.
	 }
	 
	 void backgroundWorkerThread2TabRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
	 {
		// This thread completion never getting called.
	 }
 }


If any address the issue here it would be great.

Thanks in advance.
Posted
Updated 2-Mar-18 4:27am
Comments
George Swan 3-Mar-18 1:57am    
Could I suggest that you use the Task-based Asynchronous Pattern? It is designed to obviate a lot of the problems that you are experiencing.

You don't actually start the second thread at all. Most likely, that's because you have over redacted the code - but if the DoWork event is being called (and you say it works) then you need to look very closely at the code you have in the DoWork event handler. The Completed event will only ever get handled when the DoWork handler exist - so if the code on that sits in a loop instead of returning then the thread never ends, so teh handler is never called.
 
Share this answer
 
Comments
Ramachandran P 2-Mar-18 2:59am    
Hi OriginalGriff,

Thanks for your quick response. For testing purpose, I just return from the DoWork thread. But, in this case too the completion not getting called.

Thank you.
OriginalGriff 2-Mar-18 3:31am    
So show the code where you actually start Thread 2 - include a dozen lines before and after, or the whole method.
Ramachandran P 2-Mar-18 4:01am    
Actually, The thread started inside the function HitAPIcalls().


private void function1(bool exe)
{
Wrapper wrapper = new Wrapper();
WorkerThread2 worker = wrapper.Databuff;
object outlookObject = null;
if (Inspector.CurrentItem is MailItem)
{
outlookObject = worker.OutlookMail;

}
else if (Inspector.CurrentItem is AppointmentItem)
{
outlookObject = worker.OutlookAppointment;
}
else if (Inspector.CurrentItem is ContactItem)
{
outlookObject = worker.OutlookContact;
}
CustomTaskPane taskPane = wrapper.CustomTaskPane;

if (taskPane != null)
{
if (taskPane.Visible)
{
var iFrame = taskPane.Control;
if (iFrame != null)
{
UserControlIntelV2 intelControl = (UserControlIntelV2)iFrame;
if (intelControl != null)
{
intelControl.PopulateOutlookListControl();
}
}
}
}
List<string> emailAddresses = new List<string>();
if (outlookObject is ContactItem)
{
var contactEmailAddress = worker.EmailAddressForOutlookContact((ContactItem)outlookObject);
if (!String.IsNullOrEmpty(contactEmailAddress))
{
emailAddresses.Add(contactEmailAddress);
}
}
else
{
emailAddresses = worker.GetSMTPAddressForRecipients(outlookObject);
}
var emailAddress = Utilities.FirstExternalEmail(emailAddresses);
worker.function2();
}

public void function2()
{
if (string.IsNullOrWhiteSpace(mail))
return false;

if (!Utilities.InternalOnly(mail))
{
this.email = mail;
this.HitAPIcalls(this.email);
return true;
}

return false;
}

private void HitAPIcalls(string mail)
{
// From this function, only start the background worker thread alone.
if (!backgroundWorkerThread2Tab.IsBusy)
backgroundWorkerThread2Tab.RunWorkerAsync(mail);
}
OriginalGriff 2-Mar-18 4:20am    
The chances are it is getting activated, but ... threading gets complicated!
You setup and start Thread2 from Thread1, and the setup includes the Event handler for the Completed event.
Background workers - understandably and correctly - execute the Completed event on the original thread that setup the Worker and started it - but because that is also a thread you created - Thread1 - and you told it to run asynchronously with nothing more to do in Thread 1 once the Thread2 has been started it's very, very likely that Thread1 terminates before Thread2 gets a change to activate the Completed event. Since Thread1 is no longer running, there is no execution engine available to run the code for the Completed handler (or even to notice that the handler has been activated).

Does that make sense?
Ramachandran P 2-Mar-18 5:34am    
Thanks again OriginalGriff. I just changed the code like below. But still the same problem occurred.

MainForm.cs:

public partial class MainForm : Form
{

public Form1()
{
InitializeComponent();

InspectorWrapperThread wraperThread = new InspectorWrapperThread();
wraperThread.Start();
}
}


InspectorWrapperThread.cs

public class InspectorWrapperThread : IDisposable
{

BackgroundWorker worker1;

public InspectorWrapperThread()
{

worker1 = new BackgroundWorker();
worker1.WorkerSupportsCancellation = true;
worker1.DoWork += new DoWorkEventHandler(worker1_DoWork);
worker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker1_RunWorkerCompleted);
}

void worker1_DoWork(object sender, DoWorkEventArgs e)
{
Called a function from here.
function1(true);
//Do some work here
}

void worker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// This thread completion getting called correctly.
}

private void function1(bool exe)
{
Wrapper wrapper = new Wrapper();
WorkerThread2 worker = wrapper.Databuff;
object outlookObject = null;
if (Inspector.CurrentItem is MailItem)
{
outlookObject = worker.OutlookMail;

}
else if (Inspector.CurrentItem is AppointmentItem)
{
outlookObject = worker.OutlookAppointment;
}
else if (Inspector.CurrentItem is ContactItem)
{
outlookObject = worker.OutlookContact;
}
CustomTaskPane taskPane = wrapper.CustomTaskPane;

if (taskPane != null)
{
if (taskPane.Visible)
{
var iFrame = taskPane.Control;
if (iFrame != null)
{
UserControlIntelV2 intelControl = (UserControlIntelV2)iFrame;
if (intelControl != null)
{
intelControl.PopulateOutlookListControl();
}
}
}
}
List<string> emailAddresses = new List<string>();
if (outlookObject is ContactItem)
{
var contactEmailAddress = worker.EmailAddressForOutlookContact((ContactItem)outlookObject);
if (!String.IsNullOrEmpty(contactEmailAddress))
{
emailAddresses.Add(contactEmailAddress);
}
}
else
{
emailAddresses = worker.GetSMTPAddressForRecipients(outlookObject);
}
var emailAddress = Utilities.FirstExternalEmail(emailAddresses);
worker.function2();

while (!worker.canCompleteThread)
{
if (worker.canCompleteThread)
{
break;
}
Thread.Sleep(10);
}
}
}

WorkerThread2.cs

public class WorkerThread2 : IDisposable
{
public bool canCompleteThread = false;
private BackgroundWorker backgroundWorkerThread2Tab;

public WorkerThread2()
{
backgroundWorkerThread2Tab = new BackgroundWorker();
backgroundWorkerThread2Tab.WorkerSupportsCancellation = true;
backgroundWorkerThread2Tab.DoWork += new DoWorkEventHandler(backgroundWorkerThread2TabDoWork);
backgroundWorkerThread2Tab.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerThread2TabRunWorkerCompleted);
}

public void function2()
{
if (string.IsNullOrWhiteSpace(mail))
return false;

if (!Utilities.InternalOnly(mail))
{
this.email = mail;
this.HitAPIcalls(this.email);
return true;
}

return false;
}

private void HitAPIcalls()
{
// do some operation and call
if (!backgroundWorkerThread2Tab.IsBusy)
backgroundWorkerThread2Tab.RunWorkerAsync(mail);
}

void backgroundWorkerThread2TabDoWork(object sender, DoWorkEventArgs e)
{
//This Dowork event getting called successfully and do all the operation without any issues.
}

void backgroundWorkerThread2TabRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
canCompleteThread = true
// This thread completion never getting called.
}
}
Based on the code from the comments to solution #1:

InspectorWrapperThread.cs:
C#
while (!worker.canCompleteThread)
{
    if (worker.canCompleteThread)
    {
        break;
    }
    Thread.Sleep(10);
}
WorkerThread2.cs:
C#
public bool canCompleteThread = false;
...
void backgroundWorkerThread2TabRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    canCompleteThread = true
}

You need to make the canCompleteThread field volatile:
C#
public volatile bool canCompleteThread = false;
volatile (C# Reference) | Microsoft Docs[^]
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900