我正在开发一个使用Threads的项目。在某些情况下,我遇到了这些问题:
以下是我的一些代码:
List<EmailAddress> lstEmailAddress = new List<EmailAddress>();
private void TimerCheckInternetConnection_Tick(object sender, EventArgs e)
{
lock (TicketLock)
{
if (UtilityManager.CheckForInternetConnection())
{
if (ApplicationRunStatus == Enum_ApplicationRunStatus.UnknownDisconnect || ApplicationRunStatus == Enum_ApplicationRunStatus.IsReady)
{
// Connect
ThreadPool.QueueUserWorkItem((o) =>
{
for (int i = 0; i < lstEmailAddress.Count; i++)
{
lstEmailAddress[i].IsActive = lstEmailAddress[i].Login();
}
this.BeginInvoke(new Action(() =>
{
// some code
}));
});
}
}
}
}
这是EmailAddress类:
class EmailAddress
{
private Imap4Client imap = new Imap4Client();
private object objectLock = new object();
public bool IsActive;
public string Address;
public string Password;
public string RecieveServerAddress;
public int RecieveServerPort;
public bool Login()
{
lock (objectLock)
{
try
{
imap.ConnectSsl(RecieveServerAddress, RecieveServerPort);
}
catch (Exception)
{
}
try
{
imap.Login(Address, Password);
return true;
}
catch (Exception)
{
return false;
}
}
}
}
我的问题是:
当我想使用属于Login
类的EmailAddress
过程时,它有一些冲突。正如您所看到的,我使用了Lock
,但任何事情都发生了变化。
更多详情:
如果我在lstEmailAddress
中有3个项目,则必须通过此代码调用登录过程3次。但每次登录过程都将使用相同的用户名和密码。所以我的所有电子邮件都无法正确登录。
如果我删除线程池,它就没问题了。
答案 0 :(得分:2)
您的代码非常混乱:
lock
,它将同步运行,当时只有一个线程,这将导致性能下降。QueueUserWorkItem
排队工作 - 它将在其他主题中运行,不在TicketLock
i
工作,这是being closured for it's last value,这导致你在最后一句中陈述的问题。lock
Email
类中的对象不是static
所以它是为每个实例创建的,并且实际上并不锁定anithing。
Invoke
方法时,您的代码将从UI启动,您需要传递同步上下文。我建议您使用TPL
code进行此操作,不要直接使用ThreadPool
所以我建议你这个解决方案:
List<EmailAddress> lstEmailAddress = new List<EmailAddress>();
private void TimerCheckInternetConnection_Tick(object sender, EventArgs e)
{
// remove this lock as we have another in Email class
//lock (TicketLock)
if (UtilityManager.CheckForInternetConnection())
{
if (ApplicationRunStatus == Enum_ApplicationRunStatus.UnknownDisconnect
|| ApplicationRunStatus == Enum_ApplicationRunStatus.IsReady)
{
for (int i = 0; i < lstEmailAddress.Count; i++)
{
// use local variable to store index
int localIndex = i;
// Connect
ThreadPool.QueueUserWorkItem((o) =>
{
// if you add a lock here, this will run synchroniosly,
// and you aren't really need the ThreadPool
//lock (TicketLock)
lstEmailAddress[localIndex].IsActive = lstEmailAddress[localIndex].Login();
this.BeginInvoke(new Action(() =>
{
// some code
}));
});
}
}
}
}
class EmailAddress
{
// if you have to login only for one user simultaneosly
// use static variables here, other wise simply remove the lock as it is useless
private static Imap4Client imap;
private static object objectLock;
// static constructor for only one initialization for a static fields
static EmailAddress()
{
objectLock = new object();
imap = new Imap4Client();
}
public bool IsActive;
public string Address;
public string Password;
public string RecieveServerAddress;
public int RecieveServerPort;
public bool Login()
{
// aquire a static lock
lock (objectLock)
{
try
{
imap.ConnectSsl(RecieveServerAddress, RecieveServerPort);
}
catch (Exception)
{
// STORE THE EXCEPTION!!!
// return as you haven't connected
return false;
}
try
{
imap.Login(Address, Password);
return true;
}
catch (Exception)
{
// STORE THE EXCEPTION!!!
return false;
}
}
}
}
答案 1 :(得分:-4)
将您的代码更改为并尝试。你的代码是来自lstEmailAddress的排队项目,它始终会从列表中找到最后一项。更改您的代码以查询threadpool中的每个项目。应该修复。它。
for (int i = 0; i < lstEmailAddress.Count; i++)
{
ThreadPool.QueueUserWorkItem((o) =>
{
lstEmailAddress[i].IsActive = lstEmailAddress[i].Login();
}
}