Ramachandran P Ответов: 2

Фоновый рабочий поток полное событие не запущено в C#


Привет,

В моем приложении я использовал поток backgroundworker для некоторого фонового процесса. Поток был успешно вызван, и событие Dowork выполнило всю его работу. Но после завершения события Dowork событие RunWorkerCompleted не увольняется. Любое предложение по этому поводу было бы здорово.

Здесь я приложил свой пример фрагмента кода.

Что я уже пробовал:

Форму 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.
	 }
 }


Если бы кто-нибудь обратился к этому вопросу здесь, это было бы здорово.

Заранее спасибо.

George Swan

Могу ли я предложить вам использовать асинхронный шаблон на основе задач? Он предназначен для устранения многих проблем, которые вы испытываете.

2 Ответов

Рейтинг:
1

OriginalGriff

На самом деле вы вообще не начинаете вторую нить. Скорее всего, это потому, что вы слишком отредактировали код - но если вызывается событие DoWork (и вы говорите, что оно работает), то вам нужно очень внимательно посмотреть на код, который у вас есть в обработчике событий DoWork. Завершенное событие будет обработано только тогда, когда существует обработчик DoWork - так что если код на нем сидит в цикле вместо возврата, то поток никогда не заканчивается, поэтому обработчик никогда не вызывается.


Ramachandran P

Привет OriginalGriff,

Спасибо за Ваш быстрый ответ. Для целей тестирования я просто возвращаюсь из потока DoWork. Но и в этом случае завершение не вызывается.

Спасибо.

OriginalGriff

Поэтому покажите код, где вы на самом деле начинаете поток 2 - Включите дюжину строк до и после, или весь метод.

Ramachandran P

На самом деле поток запустился внутри функции HitAPIcalls().


частный недействительными функция1(типа bool, исполняемые)
{
Обертка обертка = новая обертка();
WorkerThread2 worker = обертка.Databuff;
объект outlookObject = нуль;
если (инспектор.Текущийэлемент-это сообщения)
{
outlookObject = рабочий.OutlookMail;

}
еще если (инспектор.CurrentItem - это AppointmentItem)
{
outlookObject = рабочий.OutlookAppointment;
}
еще если (инспектор.Текущийэлемент-это Вконтактиком)
{
outlookObject = рабочий.OutlookContact;
}
CustomTaskPane панели задач = обертке.CustomTaskPane;

если (панели задач != нуль)
{
если (панели задач.Видно)
{
var iFrame = taskPane.Контроль;
if (iFrame != null)
{
UserControlIntelV2 intelControl = (UserControlIntelV2)элемент iframe;
if (intelControl != null)
{
интеллект-контроль.PopulateOutlookListControl();
}
}
}
}
List<string> emailAddresses = новый список<string>();
если (outlookObject является Вконтактиком)
{
ВАР адрес электронной почты контактного лица = работник.EmailAddressForOutlookContact((ContactItem)outlookObject);
если (!строка.IsNullOrEmpty(адрес электронной почты контактного лица))
{
адреса электронной почты.Добавить(адрес электронной почты контактного лица);
}
}
еще
{
emailAddresses = рабочий.GetSMTPAddressForRecipients(outlookObject);
}
ВАР атрибут emailaddress = коммунальные услуги.FirstExternalEmail(адреса электронной почты);
работник.функция2();
}

общественного недействительными функции function2()
{
если (строка.IsNullOrWhiteSpace(почта))
возвращать false;

если (!Коммунальные услуги.InternalOnly(почта))
{
это.электронная почта = Почта;
этот.HitAPIcalls(это.электронной почты);
вернуть true;
}

возвращать false;
}

private void HitAPIcalls(строковая почта)
{
// Из этой функции можно запустить только фоновый рабочий поток.
если (!backgroundWorkerThread2Tab.IsBusy)
backgroundWorkerThread2Tab.RunWorkerAsync(почта);
}

OriginalGriff

Есть вероятность, что он активируется, но ... резьба становится все сложнее!
Вы настраиваете и запускаете Thread2 из Thread1, и эта настройка включает обработчик событий для завершенного события.
Фоновые рабочие - понятно и правильно - выполняют завершенное событие в исходном потоке, который настроил Рабочий и запустил его, но поскольку это также созданный вами поток - Thread1 - и вы сказали ему работать асинхронно, не имея больше ничего общего с потоком 1 после запуска Thread2, очень, очень вероятно, что Thread1 завершится до того, как Thread2 получит изменение для активации завершенного события. Поскольку Thread1 больше не работает, нет никакого механизма выполнения, доступного для запуска кода для завершенного обработчика (или даже для уведомления о том, что обработчик был активирован).

Есть ли в этом смысл?

Ramachandran P

Еще раз спасибо OriginalGriff. Я просто изменил код, как показано ниже. Но все равно возникла та же проблема.

Форму mainform.в CS:

public partial class MainForm : форма
{

открытый form1()
{
метод InitializeComponent();

InspectorWrapperThread wraperThread = новый InspectorWrapperThread();
wraperThread.Начать();
}
}


InspectorWrapperThread.в CS

public class InspectorWrapperThread : IDisposable
{

BackgroundWorker worker1;

общественные InspectorWrapperThread()
{

worker1 = новый BackgroundWorker();
worker1.WorkerSupportsCancellation = истина;
worker1.DoWork += новый DoWorkEventHandler(worker1_DoWork);
worker1.RunWorkerCompleted += новый RunWorkerCompletedEventHandler(worker1_RunWorkerCompleted);
}

void worker1_DoWork(отправитель объекта, DoWorkEventArgs e)
{
Отсюда вызывается функция.
функция 1(true);
//Сделай здесь какую-нибудь работу
}

worker1_RunWorkerCompleted недействительным(объект отправителя, RunWorkerCompletedEventArgs е)
{
// Это завершение потока вызывается правильно.
}

частный недействительными функция1(типа bool, исполняемые)
{
Обертка обертка = новая обертка();
WorkerThread2 worker = обертка.Databuff;
объект outlookObject = нуль;
если (инспектор.Текущийэлемент-это сообщения)
{
outlookObject = рабочий.OutlookMail;

}
еще если (инспектор.CurrentItem - это AppointmentItem)
{
outlookObject = рабочий.OutlookAppointment;
}
еще если (инспектор.Текущийэлемент-это Вконтактиком)
{
outlookObject = рабочий.OutlookContact;
}
CustomTaskPane панели задач = обертке.CustomTaskPane;

если (панели задач != нуль)
{
если (панели задач.Видно)
{
var iFrame = taskPane.Контроль;
if (iFrame != null)
{
UserControlIntelV2 intelControl = (UserControlIntelV2)элемент iframe;
if (intelControl != null)
{
интеллект-контроль.PopulateOutlookListControl();
}
}
}
}
List<string> emailAddresses = новый список<string>();
если (outlookObject является Вконтактиком)
{
ВАР адрес электронной почты контактного лица = работник.EmailAddressForOutlookContact((ContactItem)outlookObject);
если (!строка.IsNullOrEmpty(адрес электронной почты контактного лица))
{
адреса электронной почты.Добавить(адрес электронной почты контактного лица);
}
}
еще
{
emailAddresses = рабочий.GetSMTPAddressForRecipients(outlookObject);
}
ВАР атрибут emailaddress = коммунальные услуги.FirstExternalEmail(адреса электронной почты);
работник.функция2();

хотя (!работник.canCompleteThread)
{
если (сотрудник.canCompleteThread)
{
перерыв;
}
Нить.Сон(10);
}
}
}

WorkerThread2.в CS

публичный класс WorkerThread2 : IDisposable
{
public bool canCompleteThread = false;
частный BackgroundWorker backgroundWorkerThread2Tab;

общественные WorkerThread2()
{
backgroundWorkerThread2Tab = новый BackgroundWorker();
backgroundWorkerThread2Tab.WorkerSupportsCancellation = истина;
backgroundWorkerThread2Tab.DoWork += новый DoWorkEventHandler(backgroundWorkerThread2TabDoWork);
backgroundWorkerThread2Tab.RunWorkerCompleted += новый RunWorkerCompletedEventHandler(backgroundWorkerThread2TabRunWorkercompleted);
}

общественного недействительными функции function2()
{
если (строка.IsNullOrWhiteSpace(почта))
возвращать false;

если (!Коммунальные услуги.InternalOnly(почта))
{
это.электронная почта = Почта;
этот.HitAPIcalls(это.электронной почты);
вернуть true;
}

возвращать false;
}

частные пустые HitAPIcalls()
{
// сделайте какую-нибудь операцию и позвоните
если (!backgroundWorkerThread2Tab.IsBusy)
backgroundWorkerThread2Tab.RunWorkerAsync(почта);
}

void backgroundWorkerThread2TabDoWork(отправитель объекта, DoWorkEventArgs e)
{
//Это событие Dowork вызывается успешно и выполняет всю операцию без каких-либо проблем.
}

backgroundWorkerThread2TabRunWorkercompleted недействительным(объект отправителя, RunWorkerCompletedEventArgs е)
{
canCompleteThread = истина
// Это завершение потока никогда не вызывается.
}
}

Рейтинг:
1

Richard Deeming

На основе кода из комментариев к решению №1:

InspectorWrapperThread.в CS:

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

Вам нужно сделать так, чтобы canCompleteThread поле volatile:
public volatile bool canCompleteThread = false;
фитонциды (Справочник по c#) | Майкрософт документы[^]