none
Потоковые конфликты 3 RRS feed

  • Вопрос

  • Всем привет!

    В дополнение к
    http://social.msdn.microsoft.com/Forums/ru-RU/programminglanguageru/thread/337c263c-61ed-4cc0-adb1-c058f6f99edb
    Проблема осталась не решенной для случая,
    когда нужно закрыть только вторичную форму,
    а основная форма продолжает работать.
    Все мои изыски приводят к сообщению  на Invoke -

    <<<
    Исключение типа "System.ObjectDisposedException" возникло в System.Windows.Forms.dll,
    но не было обработано в коде пользователя
    Дополнительные сведения: Cannot access a disposed object.
    >>>

    Что делать?

    public	partial	class		secondForm	:	Form
    {	private	msgGenerator	MsgGenerator;	        Action actPrint;	IAsyncResult iAsyncResult;
    	private	void		SecondForm_Closing		(	object o,FormClosingEventArgs e	)	{	Close();	}	//	Environment.Exit(0);
    	public	secondForm		()
    	{	InitializeComponent();
    		MsgGenerator=new msgGenerator();
    		actPrint = new Action	( Print	);
    		iAsyncResult=actPrint.BeginInvoke ( null,null );
    	}
    	public	void		Print	()
    	{	while (	true	)												//	Бесконечный цикл
    		{	MsgGenerator.msgCreEvent.WaitOne();	//	Ждать событие "Сообщение"
    			MsgGenerator.msgCreEvent.Reset();	//	Сбросить событие
    /**/			Invoke
    			(	new MethodInvoker
    			(	() =>
    			{	string [] s=MsgGenerator.Msg.Split('	');	//	Разделить сообщение на время и задержку
    				tbTime.Text	=	s[0];	//	Печать времени
    				tbMsg.Text=s[1];		//	Печать задержки
    			}));
    }	}	}	






    • Изменено QazRdx 8 мая 2013 г. 6:24

Ответы

  • public partial class MainForm : Form { secondForm SecondForm; private void MainForm_Closing(object o, FormClosingEventArgs e) { SecondForm.Close(); } public MainForm() { InitializeComponent(); SecondForm = new secondForm(); SecondForm.Show(); } } public partial class secondForm : Form { private messageGenerator MessageGenerator; private Action actPrint; private IAsyncResult asyncResult; private bool stopping; public secondForm() { InitializeComponent(); MessageGenerator = new messageGenerator(); actPrint = new Action(Print); asyncResult=actPrint.BeginInvoke(null, null); } public void Print() { while (!stopping) // Infinite cycle { MessageGenerator.CreateEvent.WaitOne(); // Wait event "Message is created" MessageGenerator.CreateEvent.Reset();// Event reset Invoke(new MethodInvoker (() => { TextBoxTimeDelay.Text = MessageGenerator.Message;// Message print })); } } protected override void Dispose(bool disposing){ if(disposing){ if(actPrint!=null&&asyncResult!=null){ stopping=true; actPrint.EndInvoke(asyncResult); actPrint=null; asyncResult=null; } if(MessageGenerator!=null){ MessageGenerator.Dispose(); MessageGenerator=null; } } base.Dispose(disposing); } } public class messageGenerator:IDisposable { public AutoResetEvent CreateEvent; public string Message; private Action actStart; private IAsyncResult asyncResult; private bool stopping; public messageGenerator() { CreateEvent = new AutoResetEvent(false); actStart = new Action(Start); asyncResult=actStart.BeginInvoke(null, null); } private void Start() { Random R = new Random(); while (!stopping) { int TimeDelay = 10 * R.Next(1, 5); Thread.Sleep(TimeDelay); Message = TimeDelay.ToString(); CreateEvent.Set(); // Event "Message is created" } } public void Dispose(){ Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing){ if(disposing){ if(actStart!=null&&asyncResult!=null){ stopping=true; actStart.EndInvoke(asyncResult); actStart=null; asyncResult=null; } if(CreateEvent!=null){ CreateEvent.Dispose(); CreateEvent=null; } Message=null; } } }

    • Помечено в качестве ответа QazRdx 12 мая 2013 г. 17:10
  • В общем, причину зависания я понял, осталось сообразить, как её лучше устранить.

    P.S.
    Вроде так должно работать:

    public partial class secondForm:Form{
        protected override void Dispose(bool disposing){
            if(disposing){
                if(actPrint!=null&&asyncResult!=null){
                    stopping=true;
                    if(!asyncResult.IsCompleted){
                        Application.DoEvents();
                        while(!asyncResult.IsCompleted){
                            Thread.Sleep(0);
                            Application.DoEvents();
                        }
                    }
                    actPrint.EndInvoke(asyncResult);
                    actPrint=null;
                    asyncResult=null;
                }
                if(MessageGenerator!=null){
                    MessageGenerator.Dispose();
                    MessageGenerator=null;
                }
            }
            base.Dispose(disposing);
        }
    }

    • Изменено PetSerAl 12 мая 2013 г. 12:18
    • Помечено в качестве ответа QazRdx 12 мая 2013 г. 17:09

Все ответы

  • Нашлось решение!

    В строке -
    private void SecondForm_Closing ( object o,FormClosingEventArgs e ) { Close(); }
    нужно слегка добавить, после чего она будет выглядеть  так -
    private void SecondForm_Closing ( object o,FormClosingEventArgs e ) { e.Cancel=true;   Hide(); Close   (); }

    • Помечено в качестве ответа QazRdx 8 мая 2013 г. 18:09
    • Снята пометка об ответе QazRdx 10 мая 2013 г. 5:21
  • Раненько я порадовался.
    На самом деле этот финт не закрывает вторичную форму,
    а только лишь прикрывает ее,
    т.е. убирает с экрана -
    с глаз долой.
    Но она продолжает крутиться,
    также, как и MsgGenerator.
    Т.е. ресурсы задействованы,
    но тихо и прилично.
    А хотелось-то большего -
    освобождения ресурсов.
  • Что-то и на StackOverflow.com тоже тишина -
    я даже и не ожидал, что это такая проблема.
    http://stackoverflow.com/questions/16444422/cannot-access-a-disposed-object-asynchronous-print-of-messages-in-second-form?lq=1

  • public partial class MainForm : Form { secondForm SecondForm; private void MainForm_Closing(object o, FormClosingEventArgs e) { SecondForm.Close(); } public MainForm() { InitializeComponent(); SecondForm = new secondForm(); SecondForm.Show(); } } public partial class secondForm : Form { private messageGenerator MessageGenerator; private Action actPrint; private IAsyncResult asyncResult; private bool stopping; public secondForm() { InitializeComponent(); MessageGenerator = new messageGenerator(); actPrint = new Action(Print); asyncResult=actPrint.BeginInvoke(null, null); } public void Print() { while (!stopping) // Infinite cycle { MessageGenerator.CreateEvent.WaitOne(); // Wait event "Message is created" MessageGenerator.CreateEvent.Reset();// Event reset Invoke(new MethodInvoker (() => { TextBoxTimeDelay.Text = MessageGenerator.Message;// Message print })); } } protected override void Dispose(bool disposing){ if(disposing){ if(actPrint!=null&&asyncResult!=null){ stopping=true; actPrint.EndInvoke(asyncResult); actPrint=null; asyncResult=null; } if(MessageGenerator!=null){ MessageGenerator.Dispose(); MessageGenerator=null; } } base.Dispose(disposing); } } public class messageGenerator:IDisposable { public AutoResetEvent CreateEvent; public string Message; private Action actStart; private IAsyncResult asyncResult; private bool stopping; public messageGenerator() { CreateEvent = new AutoResetEvent(false); actStart = new Action(Start); asyncResult=actStart.BeginInvoke(null, null); } private void Start() { Random R = new Random(); while (!stopping) { int TimeDelay = 10 * R.Next(1, 5); Thread.Sleep(TimeDelay); Message = TimeDelay.ToString(); CreateEvent.Set(); // Event "Message is created" } } public void Dispose(){ Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing){ if(disposing){ if(actStart!=null&&asyncResult!=null){ stopping=true; actStart.EndInvoke(asyncResult); actStart=null; asyncResult=null; } if(CreateEvent!=null){ CreateEvent.Dispose(); CreateEvent=null; } Message=null; } } }

    • Помечено в качестве ответа QazRdx 12 мая 2013 г. 17:10
  • Увы!

    Этот вариант тоже не работает.
    При нажатии на CancelButton
    обе формы, MainForm и SecondForm, блокируются
    и висят пока я не завершаю процесс TaskManager - ом.
    Причем, такое завершение удаляет формы с экрана,
    но сам процесс устойчиво продолжает висеть,
    т.е. после каждой моей попытки его завершить,
    он якобы завершается, но потом неизменно восстанавливается,
    занимая ~ 2-3 мб памяти и
    практически не загружая процессор.
    Удаление, комментирование, строки в методе MessageGenerator.Dispose,
    которая не позволяет завершить процесс для заданного объекта -
    GC.SuppressFinalize(this);
    практически ничего не меняет.
    Удаляет этот процесс только перезагрузка системы.

    Использование
    переменной SecondForm.stopping и
    методов
    SecondForm.actPrint.EndInvoke(asyncResult) и
    MessageGenerator.actStart.EndInvoke(asyncResult)
    я уже пробовал - безрезультатно.

    Какое-то наваждение!
    Вроде никакой экзотики нет -
    нужно просто закрыть вторичную форму.
    И никак !..
    Может быть, это майкросовтовские грешки?


    • Изменено QazRdx 12 мая 2013 г. 4:58
  • Выкладывайте весь проект целиком. Может быть у Вас проблема где-нибудь в другом месте.

    P.S.
    GC.SuppressFinalize(this); только исключает объект из очереди финализации, а не

    не позволяет завершить процесс для заданного объекта
  • // MainForm.cs
    	using System;
    	using System.Threading;
    	using System.Windows.Forms;
    	namespace	ThreadTree
    {	public partial class MainForm : Form
    	{	secondForm SecondForm;
    		private void MainForm_Closing	(	object o, FormClosingEventArgs e	)		{	SecondForm.Close();	}
    		public MainForm()
    		{	InitializeComponent();
    			SecondForm = new secondForm();
    			SecondForm.Show();
    	}	}	
    	public partial class secondForm : Form
    	{	private messageGenerator MessageGenerator;
    		private Action actPrint;
    		private IAsyncResult asyncResult;
    		private bool stopping;
    //		private		void				SecondForm_Closing	(	object o,FormClosingEventArgs e	)	{	Close();	}		//	e.Cancel=true;	Hide();		Parent=null;		}	//	Close();	Application.DoEvents();	}
    		private		void				SecondForm_Closing	(	object o,FormClosingEventArgs e	)	{	Dispose();	}		//	e.Cancel=true;	Hide();		Parent=null;		}	//	Close();	Application.DoEvents();	}
    		public secondForm()
    		{	InitializeComponent();
    			MessageGenerator = new messageGenerator();
    			actPrint = new Action(Print);
    			asyncResult=actPrint.BeginInvoke(null, null);
    		}
    		public void Print()
    		{	while (!stopping)   //  Infinite  cycle
    			{	MessageGenerator.CreateEvent.WaitOne(); //  Wait event "Message is created"
    				MessageGenerator.CreateEvent.Reset();//  Event reset
    				Invoke(new MethodInvoker
    				(() =>
    				{	TextBoxTimeDelay.Text = MessageGenerator.Message;//  Message print
    				}));
    		}	}
    		protected	override	void	Dispose(bool disposing){
    			if	(	disposing	)
    			{	if	(	actPrint!=null	&&	asyncResult!=null	)
    				{	stopping=true;
    					actPrint.EndInvoke(asyncResult);
    					actPrint=null;
    					asyncResult=null;
    				}
    				if	(	MessageGenerator!=null	)
    				{	MessageGenerator.Dispose();
    					MessageGenerator=null;
    			}	}	base.Dispose	(	disposing	);
    	}	}
    
    
    
    	public class messageGenerator:IDisposable
    	{	public AutoResetEvent CreateEvent;
    		public string Message;
    		private Action actStart;
    		private IAsyncResult asyncResult;
    		private bool stopping;
    		public messageGenerator()
    		{	CreateEvent = new AutoResetEvent(false);
    			actStart = new Action(Start);
    			asyncResult=actStart.BeginInvoke(null, null);
    		}
    		private void Start()
    		{	Random R = new Random();
    			while (!stopping)
    			{	int TimeDelay = 10 * R.Next(1, 5);
    				Thread.Sleep(TimeDelay);
    				Message = TimeDelay.ToString();
    				CreateEvent.Set();  //  Event "Message is created"
    		}	}
    		public void Dispose	()
    		{	Dispose(true);
    //			GC.SuppressFinalize(this);
    		}
    		protected virtual void Dispose	(	bool disposing	)
    		{	if	(disposing)
    			{	if	(	actStart!=null&&asyncResult!=null	)
    				{	stopping=true;
    					actStart.EndInvoke(asyncResult);
    					actStart=null;
    					asyncResult=null;
    				}
    			    if	(	CreateEvent!=null	)
    				{	CreateEvent.Dispose();
    					CreateEvent=null;
    				}	Message=null;
    }	}	}	}	
    
    
    // MainForm.Designer.cs
    
    ee
    {	partial class MainForm
    	{	private		System.ComponentModel.IContainer components = null;
    		protected	override	void Dispose	(	bool disposing)	{	if (disposing && (components != null)) {	components.Dispose();	}	base.Dispose(disposing);	}
    		#region		WindowsFormConstructor
    		private		void	InitializeComponent() 
    		{	this.tbTimeDelay = new System.Windows.Forms.TextBox();
    			this.rtbCrrEvents = new System.Windows.Forms.RichTextBox();
    			this.tbTime = new System.Windows.Forms.TextBox();
    			this.btStart = new System.Windows.Forms.Button();
    			this.SuspendLayout();
    			// 
    			// tbTimeDelay
    			// 
    			this.tbTimeDelay.Location = new System.Drawing.Point(168, 3);
    			this.tbTimeDelay.Name = "tbTimeDelay";
    			this.tbTimeDelay.Size = new System.Drawing.Size(50, 20);
    			this.tbTimeDelay.TabIndex = 1;
    			// 
    			// rtbCrrEvents
    			// 
    			this.rtbCrrEvents.Location = new System.Drawing.Point(5, 30);
    			this.rtbCrrEvents.Name = "rtbCrrEvents";
    			this.rtbCrrEvents.Size = new System.Drawing.Size(270, 125);
    			this.rtbCrrEvents.TabIndex = 2;
    			this.rtbCrrEvents.Text = "";
    			// 
    			// tbTime
    			// 
    			this.tbTime.Location = new System.Drawing.Point(112, 3);
    			this.tbTime.Name = "tbTime";
    			this.tbTime.Size = new System.Drawing.Size(50, 20);
    			this.tbTime.TabIndex = 3;
    			// 
    			// btStart
    			// 
    			this.btStart.Location = new System.Drawing.Point(222, 3);
    			this.btStart.Name = "btStart";
    			this.btStart.Size = new System.Drawing.Size(52, 20);
    			this.btStart.TabIndex = 4;
    			this.btStart.Text = "Start";
    			this.btStart.UseVisualStyleBackColor = true;
    			// 
    			// MainForm
    			// 
    			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    			this.ClientSize = new System.Drawing.Size(284, 162);
    			this.Controls.Add	(this.btStart);
    			this.Controls.Add	(this.tbTime);
    			this.Controls.Add	(this.rtbCrrEvents);
    			this.Controls.Add	(this.tbTimeDelay);
    			this.Name = "MainForm";
    			this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
    			this.Text = "MainForm";
    			this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_Closing);
    			this.ResumeLayout(false);
    			this.PerformLayout();
    		}
    		#endregion
    		private System.Windows.Forms.TextBox			tbTimeDelay; 
    		private System.Windows.Forms.RichTextBox	rtbCrrEvents;
    		private System.Windows.Forms.TextBox			tbTime;
    		private System.Windows.Forms.Button			btStart;
    }	}
    
    
    // SecondForm.Designer.cs
    
    namespace ThreadTree
    {	public partial class secondForm
    	{	private System.ComponentModel.IContainer components = null;
    //		protected override void Dispose(bool disposing)	{	if (disposing && (components != null))	{	components.Dispose();		}	base.Dispose(disposing);	}
    		#region Windows Form Designer
    		private void InitializeComponent		()
    		{	this.components					=	new System.ComponentModel.Container();
    			this.TextBoxTimeDelay		=	new System.Windows.Forms.TextBox();
    			this.ToolTip							=	new System.Windows.Forms.ToolTip(this.components);
    			this.SuspendLayout();
    			// 
    			// tbTime
    			// 
    			this.TextBoxTimeDelay.Location	= new System.Drawing.Point(3, 3);
    			this.TextBoxTimeDelay.Name			= "textBoxTimeDelay";
    			this.TextBoxTimeDelay.Size			= new System.Drawing.Size(50, 20);
    			this.TextBoxTimeDelay.TabIndex	= 10;
    			this.ToolTip.SetToolTip(this.TextBoxTimeDelay, "TimeDelay");
    			// 
    			// secondForm
    			// 
    			this.AutoScaleDimensions	=	new System.Drawing.SizeF(6F, 13F);
    			this.AutoScaleMode				=	System.Windows.Forms.AutoScaleMode.Font;
    			this.Size								=	new System.Drawing.Size(300, 200);
    			this.Controls.Add					(	TextBoxTimeDelay	);
    			this.Location						=	new System.Drawing.Point(300, 0);
    			this.Name = "twoForm";
    			this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
    			this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(SecondForm_Closing);
    			this.ResumeLayout(false);
    			this.PerformLayout();
            }
            #endregion
    		public		System.Windows.Forms.TextBox			TextBoxTimeDelay;
    		public		System.Windows.Forms.ToolTip			ToolTip;
    }	}	
    
    // Program.cs
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace ThreadTree
    {	static class Program
    	{	[STAThread]
    		static	void		Main	()
    		{	Application.EnableVisualStyles();
    			Application.SetCompatibleTextRenderingDefault(false);
    			Application.Run(new MainForm());
    }	}	}	

  • Извиняюсь!
    Должен отлучиться часов на 8-10.
  • Один вопросик: что за дьявольское форматирование кода? Это какой стандарт? о.О

    DreamSpark Premium User

  • В общем, причину зависания я понял, осталось сообразить, как её лучше устранить.

    P.S.
    Вроде так должно работать:

    public partial class secondForm:Form{
        protected override void Dispose(bool disposing){
            if(disposing){
                if(actPrint!=null&&asyncResult!=null){
                    stopping=true;
                    if(!asyncResult.IsCompleted){
                        Application.DoEvents();
                        while(!asyncResult.IsCompleted){
                            Thread.Sleep(0);
                            Application.DoEvents();
                        }
                    }
                    actPrint.EndInvoke(asyncResult);
                    actPrint=null;
                    asyncResult=null;
                }
                if(MessageGenerator!=null){
                    MessageGenerator.Dispose();
                    MessageGenerator=null;
                }
            }
            base.Dispose(disposing);
        }
    }

    • Изменено PetSerAl 12 мая 2013 г. 12:18
    • Помечено в качестве ответа QazRdx 12 мая 2013 г. 17:09
  • Этот вариант лучше -
    формы закрываются, как им и положено.
    Но процесс не завершается
    даже удалением с помощью TaskManager-а.
    Т.е. даже тогда, когда формы закрыты,
    TaskManager показывает,
    что память занята тем же объемом,
    что и в рабочем состоянии,
    когда формы были на экране.
  • Лично я не наблюдал такого поведения. У меня процесс прекрасно закрывался и сам, и через Process Explorer, и через встроенный Task Manager. Возможно какая-то проблема именно с Вашим компьютером. Попробуйте запустить программу на другом компьютере или в виртуальной машине. Я даже не представляю, как эта программа может блокировать своё закрытие операционной системой.
  • Да! Все правильно! Отлично!
    Большое Вам спасибо!
    А вообще-то майкрософт мог бы и попроще решить такую проблему.
    Ведь понятно же, если я закрываю вторичную форму,
    то значит следует закрыть и все то, 
    что с ней связано.
    В следующий раз я вряд ли смогу повторить по памяти все эти манипуляции с 
    Dispose.
    Будем надеяться, что все это будет преодолено.
    Еще раз спасибо!
  • Проблема в том, что невозможно надёжно определить всё что связанно с формой, что из этого требует особых действий при закрытии, каких действий и в каком порядке, поэтому такие действия необходимо описывать явно. В любом случае Вы ведь не удаляете каждый контрол, добавленный на форму, это делается за Вас. А дизайнер предоставляет базовую имплементацию Dispose:
    protected override void Dispose(bool disposing){
        if(disposing && (components != null)){
            components.Dispose();
        }
        base.Dispose(disposing);
    }
    которая обеспечивает удаление компонентов, добавленных на форму. Собственно, если бы Вы оформили генератор и получатель сообщений в виде компонентов, то Вы бы могли бы легко кинуть их на форму как ToolTip и не заботиться о их ручном удалении.
  • "...если бы Вы оформили генератор и получатель сообщений в виде компонентов..."

    Как это?
    Пожалуйста, если не трудно!
    Я с этим не знаком!

  • Впрочем, есть, что почитать
    и есть, в чем разобраться.
    Еще раз большое спасибо!
    • Изменено QazRdx 12 мая 2013 г. 20:59