نوشته شده توسط
mehdi.mousavi
سلام.
واژه Thread-Safe ربطي به .NET Framework نداره و قبل از اونهم توسط برنامه نويسان C/C++ استفاده ميشده (اگر چه اونها Synchronization رو بيشتر استفاده ميکنن)، بنابراين اين بخش از گفته شما که "بقول دات نت کارها..." چندان صحيح نيست.
سلام، مثل همیشه آقا مهدی خشن! حالا چندان صحیح نباشه، چی میشه مگه؟ میخواستم زود با بچه ها پسرخاله بشیم، تحویلمون بگیرن ...
نوشته شده توسط
mehdi.mousavi
برای Cancel کردن Worker Thread هم میتونید از CancelAsync استفاده کنید. فقط حواستون باشه که خودتون باید توی Interval های دلخواهتون CancellationPending رو چک کنید تا اگر true بود، کار Worker Thread رو خاتمه داده و از تابع DoWork خارج بشید. (این کار مایکروسافت واقعا احمقانه بوده، جای اینکه Event رو بشه Signal کرد و ... اومده از یک متغیر boolean برای cancel کردن کار استفاده میکنه. که خوب، اگر برنامه نویس حواسش نباشه، کد نهایی cpu-usage رو میتونه بالا ببره).
بیخیال Cancle، آقا من تو working اش مشکل دارم!
از راهنمایی هاتون خیلی مرسی، دو قرونی افتاد و با توضیحات شما و راهنمایی های MSDN کد من شد بصورت زیر :
یعنی بجای CallBack از BackgroundWorker استفاده کردم.
private void bgwTablUpdater_DoWork(object sender, DoWorkEventArgs e)
{
bool bAllTransfered = true;
if ((MessageBox.Show("Are you sure to update all tables?", "Warning",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1) == DialogResult.Yes) &&
(lstboxTables.Items.Count > 0))
{
int idx, iPercent = 0;
for (idx = 0; idx < lstboxTables.Items.Count; idx++)
{
try
{
Select_TableItem(idx);
iPercent = (idx * 100) / lstboxTables.Items.Count;
DataSet setting_ds = hotbill.GetHotBillTableContents(lstboxTables.Items[idx].ToString());
bgwTablUpdater.ReportProgress(iPercent, string.Format("[{0}] Table <{1}> have [{2}] records.",
idx + 1,
lstboxTables.Items[idx].ToString(),
setting_ds.Tables[0].Rows.Count));
if (setting_ds.Tables.Count > 0)
{
Update_dataGV(setting_ds.Tables[0]);
int tdx = sqlTablesList.IndexOf(lstboxTables.Items[idx].ToString());
if (!transferTable(lstboxTables.Items[idx].ToString(),
setting_ds.Tables[0],
(tdx >= 0)))
break;
}
}
catch (Exception ex)
{
bgwTablUpdater.ReportProgress(iPercent, "[ER]: "+ex.Message);
bAllTransfered = false;
}
}
if (bAllTransfered)
bgwTablUpdater.ReportProgress(100, "Process Completed Successfull.");
else
bgwTablUpdater.ReportProgress(-1, "[WR] Process Not Completed.");
}
else
MessageBox.Show("There is not any Update Table existed in list!"
+ "\nTry \"Get HotBill Tables\" first", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
//=================
private void bgwTablUpdater_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
AddText(string.Format("[{0}%] : {1}",
(e.ProgressPercentage).ToString() +
e.UserState as string));
}
//=================
private void bgwTablUpdater_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
AddText("Written by the main thread after the background thread completed.");
}
//=================
private void btnUpdateSettings_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Are you sure to update all tables?", "Warning",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1) == DialogResult.Yes)
{
btnUpdateSettings.Enabled = false;
bgwTablUpdater.DoWork += new DoWorkEventHandler(bgwTablUpdater_DoWork);
bgwTablUpdater.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwTablUpdater_RunW orkerCompleted);
bgwTablUpdater.ProgressChanged += new ProgressChangedEventHandler(bgwTablUpdater_Progres sChanged);
bgwTablUpdater.WorkerReportsProgress = true;
bgwTablUpdater.RunWorkerAsync();
}
}
یه سوال : نام توابعی که از ترکیب پسوندها (DoWork و RunWorkerCompleted و ...) و نام تابع اصلی درست میشن و Event Handler ها رو درست می کنند، میشه عوض بشن؟ یعنی نام تابع من یه چیز دیگه باشه : مثلاً bgwTablUpdater_DoWork بشه DoWorkTablUpdater، فکر نکنم نشه! چون من دارم دستی Event Handler رو اختصاص میدم، درسته؟
مشکل : یک استثناء یا بهتر اگر گویم : اعتراض (بیگانگان Exception گویند) خفن دریافت می کنیم، بدین سان : Exception has been thrown by the target of an invocation.
و جزئیات اش مشتمل بر موارد ذیل می گردد:
System.Reflection.TargetInvocationException was unhandled
Message="Exception has been thrown by the target of an invocation."
Source="mscorlib"
StackTrace:
at System.RuntimeMethodHandle._InvokeMethodFast(Objec t target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at System.Windows.Forms.Control.InvokeMarshaledCallba ckDo(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallba ckHelper(Object obj)
at System.Threading.ExecutionContext.runTryCode(Objec t userData)
at System.Runtime.CompilerServices.RuntimeHelpers.Exe cuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(Exec utionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionCon text executionContext, ContextCallback callback, Object state)
at System.Windows.Forms.Control.InvokeMarshaledCallba ck(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallba cks()
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.O nMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.W ndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallba ck(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchM essageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager. System.Windows.Forms.UnsafeNativeMethods.IMsoCompo nentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.Run MessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.Run MessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at TestHotBilling.Program.Main() in ..\..\Program.cs:line 17
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.Run UsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context( Object state)
at System.Threading.ExecutionContext.Run(ExecutionCon text executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: System.FormatException
Message="Index (zero based) must be greater than or equal to zero and less than the size of the argument list."
Source="mscorlib"
StackTrace:
at System.Text.StringBuilder.AppendFormat(IFormatProv ider provider, String format, Object[] args)
at System.String.Format(IFormatProvider provider, String format, Object[] args)
at System.String.Format(String format, Object arg0)
at TestHotBilling.frmHotBilling.bgwTablUpdater_Progre ssChanged(Object sender, ProgressChangedEventArgs e) in F:\Projects\ElkaHtoBillingService\TestThread\frmTe sterMain.cs:line 602
at System.ComponentModel.BackgroundWorker.OnProgressC hanged(ProgressChangedEventArgs e)
at System.ComponentModel.BackgroundWorker.ProgressRep orter(Object arg)
InnerException:
احتمال بر ذخیره نمودن رویدادها در فایل میرود، شما چنین نمی پندارید؟ یا شاید هم سبب این باشد که ما تابع Update_dataGV را استفاده کرده (و آن نیز به نوبه خود از "رویه طلب نمودن" و به زبان باختر : InvokeMethod مستفیذ گردیده است) و سبب بروز مشکلاتی از این قسم می گردد ...
(امیدوارم با این جمله بندی دیگه اشکال نحوی به من نگیرید : شوخی بود ها... ناراحت نشین!)
بازم از توجهتون ممنون.