一个关于多线程的问题

bbjiabcd 2012-08-01 04:15:15
我要在WinForm里实现这样一个功能:点击一个按钮,程序创建一个新后台线程,处理一个需要一定时间的任务(比如:发电子邮件或者复制文件等),此时,主窗体不能没有响应。处理完后,返回操作结果,主窗体显示处理结果。在处理时,主窗体能显示处理进度更好。
最好能提供示例代码。本人菜鸟,望赐教。
...全文
215 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
bbjiabcd 2012-08-02
  • 打赏
  • 举报
回复
算了,关于传回参数的问题,在此不深究了。
以上程序已经没有错误,并且能够达到目的了。
谢谢所有回帖的热心朋友!
bbjiabcd 2012-08-02
  • 打赏
  • 举报
回复
程序现在改成这样,没有问题了,传递参数和回调已经实现。就是传回参数时,用的是全局变量,闭包还是没搞懂。
public class ResultShow
{
public bool Success;
public string ErrMessage;
public ResultShow()
{
Success = false;
ErrMessage = "";
}
public ResultShow(bool suc)
{
Success = suc;
if (suc)
ErrMessage = "";
else
ErrMessage = "Unknown Error";
}
public ResultShow(bool suc, string errm)
{
Success = suc;
if (suc)
ErrMessage = "";
else
ErrMessage = errm;
}
}

public static ResultShow r1 = new ResultShow();
public delegate void MyInvoke();

private void SendEmail(object msg)
{
try
{
client.Send((MailMessage)msg);
r1.Success = true;
}
catch (Exception ex)
{
r1.Success = false;
r1.ErrMessage = ex.Message;
}
MyInvoke mi = new MyInvoke(SendEnd);
this.BeginInvoke(mi);
}

private void SendEnd()
{
if (r1.Success)
{
tSSlblStatus.Text = "发送完成";
MessageBox.Show("发送成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
tSSlblStatus.Text = "发送失败";
MessageBox.Show(r1.ErrMessage, "发送邮件出错", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
tSSlblStatus.Text = "";
txtReceive.Enabled = true;
txtTitle.Enabled = true;
txtNeirong.Enabled = true;
btSend.Enabled = true;
btSettings.Enabled = true;
cByxj.Enabled = true;
}

private void btSend_Click(object sender, EventArgs e)
{
tSSlblStatus.Text = "准备发送...";
txtReceive.Enabled = false;
txtTitle.Enabled = false;
txtNeirong.Enabled = false;
btSend.Enabled = false;
btSettings.Enabled = false;
cByxj.Enabled = false;
string mailContent = txtNeirong.Text;

MailMessage msg = new System.Net.Mail.MailMessage();
...
Thread thread = new Thread(new ParameterizedThreadStart(SendEmail));
thread.IsBackground = true;
tSSlblStatus.Text = "正在发送邮件...";
thread.Start(msg);
}
bbjiabcd 2012-08-02
  • 打赏
  • 举报
回复
我不想用Control.CheckForIllegalCrossThreadCalls = false;的方法
不想在子线程中控制主窗体的控件。
MessageBox.Show("发送成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
MessageBox.Show(ex.Message, "发送邮件出错", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
tSSlblStatus.Text = "";
txtReceive.Enabled = true;
txtTitle.Enabled = true;
txtNeirong.Enabled = true;
btSend.Enabled = true;
btSettings.Enabled = true;
cByxj.Enabled = true;

我希望把这些语句放到主窗体中。
因此必须在子线程运行完成后传送一个参数给主窗体,由主窗体执行这些语句。
怎样才能实现?
SocketUpEx 2012-08-02
  • 打赏
  • 举报
回复
using System;
using System.Threading;

namespace Test
{
class Program
{

private static void Foo(Object obj)
{
if(obj != null)
{
ThreadData threadData = obj as ThreadData;
if (threadData != null)
{
Console.WriteLine(String.Format("ThreadName={0},RunTime={1}", threadData.ThreadName, threadData.RunTime));
}
}
}

static void Main()
{
ThreadData threadData = new ThreadData();
threadData.ThreadName = "TestThread";
threadData.RunTime = System.DateTime.Now;

Thread t = new Thread(new ParameterizedThreadStart(Foo));
t.IsBackground = true;
t.Start(threadData);

Console.ReadKey();
}
}

class ThreadData
{
public String ThreadName;
public DateTime RunTime;
}
}


gao117348222 2012-08-02
  • 打赏
  • 举报
回复
用background控件呗
xboxeer 2012-08-02
  • 打赏
  • 举报
回复
1:利用lambda表达式做闭包
2:在上面闭包的基础上传递一个委托进去 线程返回时回调 或者用Task什么的来做 这个支持异步回调的
[Quote=引用 11 楼 的回复:]

现在网上很多关于 线程间通信 的资料都讲的是:如何子线程来控制UI中的控件。
而我要问的是:1、如何给线程传递一个参数,难道必须用全局变量?
2、如何在线程返回时,传递一个参数给主窗体,并使主窗体执行一个方法来响应(这个参数必须用全局变量?)
[/Quote]
bbjiabcd 2012-08-02
  • 打赏
  • 举报
回复
现在网上很多关于 线程间通信 的资料都讲的是:如何子线程来控制UI中的控件。
而我要问的是:1、如何给线程传递一个参数,难道必须用全局变量?
2、如何在线程返回时,传递一个参数给主窗体,并使主窗体执行一个方法来响应(这个参数必须用全局变量?)
SocketUpEx 2012-08-02
  • 打赏
  • 举报
回复
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}

加上CheckForIllegalCrossThreadCalls = false就行了
bbjiabcd 2012-08-02
  • 打赏
  • 举报
回复
可能上面的问题表述不够清楚,我再重新说下
private void SendEmail()
{
try
{
client.Send(msg);
tSSlblStatus.Text = "发送完成";
MessageBox.Show("发送成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
tSSlblStatus.Text = "发送失败";
MessageBox.Show(ex.Message, "发送邮件出错", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
tSSlblStatus.Text = "";
txtReceive.Enabled = true; //这几句设置Enable的语句会出错
txtTitle.Enabled = true;
txtNeirong.Enabled = true;
btSend.Enabled = true;
btSettings.Enabled = true;
cByxj.Enabled = true;
}

private void btSend_Click(object sender, EventArgs e)
{
tSSlblStatus.Text = "准备发送...";
txtReceive.Enabled = false;
txtTitle.Enabled = false;
txtNeirong.Enabled = false;
btSend.Enabled = false;
btSettings.Enabled = false;
cByxj.Enabled = false;
...
Thread thread = new Thread(new ThreadStart(SendEmail));
tSSlblStatus.Text = "正在发送邮件...";
thread.Start();
}

这是我编的发送电子邮件的例子。线程结束前,需要将发送成功,或者失败的信息传送给主窗体,将MessageBox显示和改变控件Text、Enable的代码移到主窗体中,最好能将这些代码放进一个新的方法中,当主窗体收到线程的消息时执行这个方法。
SocketUpEx 2012-08-01
  • 打赏
  • 举报
回复
尼玛
吃了饭重看这张帖
才发现
我给的代码根本不是多线程
是委托事件的例子



SocketUpEx 2012-08-01
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]
你不如直接用C写了
[/Quote]

不要这样喂
不要这样喂
Directory.GetFiles太垃圾了
竟然不是异步的
文件一多
就有可能卡死界面
有木有?
有木有?


bigbaldy 2012-08-01
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]

拷贝文件的例子


C# code


类代码:
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

namespace WindowsFormsApplication1
{
/// <summary>
/// 继续滥用委托
//……
[/Quote]

你不如直接用C写了
SocketUpEx 2012-08-01
  • 打赏
  • 举报
回复
拷贝文件的例子




类代码:
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

namespace WindowsFormsApplication1
{
/// <summary>
/// 继续滥用委托
/// </summary>
/// <param name="sourceFile"></param>
/// <param name="targetFile"></param>
public delegate void CopyProgressHandler(String sourceFile, String targetFile);

/// <summary>
/// 拷贝文件夹类
/// </summary>
public class CopyDirectory
{
/// <summary>
/// 继续滥用事件
/// </summary>
public event CopyProgressHandler CopyProgress;

#region Win32 API

private const int MAX_PATH = 260;
private const int MAX_ALTERNATE = 14;

[StructLayout(LayoutKind.Sequential)]
private struct FILETIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WIN32_FIND_DATA
{
public FileAttributes dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public uint nFileSizeHigh; //changed all to uint from int, otherwise you run into unexpected overflow
public uint nFileSizeLow; //| http://www.pinvoke.net/default.aspx/Structures/WIN32_FIND_DATA.html
public uint dwReserved0; //|
public uint dwReserved1; //v
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ALTERNATE)]
public string cAlternate;
}

[DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FindClose(IntPtr hFindFile);

#endregion

/// <summary>
/// 拷贝
/// </summary>
/// <param name="sourceDirectory">源文件</param>
/// <param name="targetDirectory">目标文件夹</param>
public void Copy(String sourceDirectory, String targetDirectory)
{
IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
WIN32_FIND_DATA findData;

IntPtr findHandle;

findHandle = FindFirstFile(sourceDirectory + "*.*", out findData);
if (findHandle != INVALID_HANDLE_VALUE)
{
do
{
if ((findData.dwFileAttributes & FileAttributes.Directory) != 0)
{
if (findData.cFileName != "." && findData.cFileName != "..")
{
Copy(String.Format("{0}{1}{2}", sourceDirectory, findData.cFileName, "\\"), targetDirectory);
}
}
else
{
String strFile = sourceDirectory + findData.cFileName;
if (File.Exists(strFile))
{
try
{
FileInfo fileInfo = new FileInfo(strFile);
String strCopyTargetFile = String.Format("{0}{1}", targetDirectory, fileInfo.Name);
if (CopyProgress != null)
{
// 触发事件,通知界面
CopyProgress(strFile, strCopyTargetFile);
}
// 拷贝文件
File.Copy(strFile, strCopyTargetFile);
}
catch
{
}
}
}
}
while (FindNextFile(findHandle, out findData));
FindClose(findHandle);
}
}
}
}




窗体代码:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

namespace WindowsFormsApplication1
{
/// <summary>
/// 继续滥用委托
/// </summary>
/// <param name="sourceFile"></param>
/// <param name="targetFile"></param>
public delegate void CopyProgressHandler(String sourceFile, String targetFile);

/// <summary>
/// 拷贝文件夹类
/// </summary>
public class CopyDirectory
{
/// <summary>
/// 继续滥用事件
/// </summary>
public event CopyProgressHandler CopyProgress;

#region Win32 API

private const int MAX_PATH = 260;
private const int MAX_ALTERNATE = 14;

[StructLayout(LayoutKind.Sequential)]
private struct FILETIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WIN32_FIND_DATA
{
public FileAttributes dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public uint nFileSizeHigh; //changed all to uint from int, otherwise you run into unexpected overflow
public uint nFileSizeLow; //| http://www.pinvoke.net/default.aspx/Structures/WIN32_FIND_DATA.html
public uint dwReserved0; //|
public uint dwReserved1; //v
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ALTERNATE)]
public string cAlternate;
}

[DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FindClose(IntPtr hFindFile);

#endregion

/// <summary>
/// 拷贝
/// </summary>
/// <param name="sourceDirectory">源文件</param>
/// <param name="targetDirectory">目标文件夹</param>
public void Copy(String sourceDirectory, String targetDirectory)
{
IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
WIN32_FIND_DATA findData;

IntPtr findHandle;

findHandle = FindFirstFile(sourceDirectory + "*.*", out findData);
if (findHandle != INVALID_HANDLE_VALUE)
{
do
{
if ((findData.dwFileAttributes & FileAttributes.Directory) != 0)
{
if (findData.cFileName != "." && findData.cFileName != "..")
{
Copy(String.Format("{0}{1}{2}", sourceDirectory, findData.cFileName, "\\"), targetDirectory);
}
}
else
{
String strFile = sourceDirectory + findData.cFileName;
if (File.Exists(strFile))
{
try
{
FileInfo fileInfo = new FileInfo(strFile);
String strCopyTargetFile = String.Format("{0}{1}", targetDirectory, fileInfo.Name);
if (CopyProgress != null)
{
// 触发事件,通知界面
CopyProgress(strFile, strCopyTargetFile);
}
// 拷贝文件
File.Copy(strFile, strCopyTargetFile);
}
catch
{
}
}
}
}
while (FindNextFile(findHandle, out findData));
FindClose(findHandle);
}
}
}
}


bigbaldy 2012-08-01
  • 打赏
  • 举报
回复
private void button1_Click(object sender, EventArgs e)
{
new Thread(() =>
{
for(int i=0;i<10000;i++)
{
Invoke((MethodInvoker)(() => { progressBar1.Value = i; }));
}
}).Start();
}
bbjiabcd 2012-08-01
  • 打赏
  • 举报
回复
前2个函数和第一行的声明,能解释一下吗?
bdmh 2012-08-01
  • 打赏
  • 举报
回复

private delegate void SetProgressBar(int value);
private void SetPBar(int value)
{
if (this.InvokeRequired)
this.Invoke(new Action<int>(SetPBar), value);
else
{
this.progressBar1.Value = value;
}
}
private void SetValue()
{
SetProgressBar setbar = new SetProgressBar(SetPBar);
for (int i = 0; i < 100000; i++)
{
setbar.Invoke(i);
}
}
private void button10_Click(object sender, EventArgs e)
{
progressBar1.Maximum = 100000;
Thread thread = new Thread(new ThreadStart(SetValue));
thread.Start();
}

110,571

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧