我正在使用线程的项目。在某些情况下,我有以下问题:
这是我的一些代码:
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个项目,则此代码必须将Login过程调用3次。但每次登录过程都将使用相同的用户名和密码。因此,我所有的电子邮件都无法正确登录。如果我删除线程池,就可以了。
最佳答案
您的代码非常困惑:
lock
,它将同步运行,一次仅运行一个线程,这将导致性能下降。 QueueUserWorkItem
排队工作-它会在其他线程中运行,并且不在TicketLock
内 i
,即being closured for it's last value,它会导致您在最后一句中指出的问题。 lock
类中的Email
对象不是static
,因此它是为每个实例创建的,实际上并没有锁定。 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;
}
}
}
}