线程在某些情况下发生冲突,在循环条件下
Threads conflict in some cases, in loop conditions
我正在从事一个使用线程的项目。在某些情况下,我遇到了这些问题:
这是我的部分代码:
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
}));
});
}
}
}
}
这是电子邮件地址 class :
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;
}
}
}
}
我的问题是:
当我想使用属于EmailAddress
Class的Login
过程时,它有一些冲突。如您所见,我使用了 Lock
但任何东西都变了。
更多详情:
如果我在 lstEmailAddress
中有 3 个项目,则此代码必须调用登录过程 3 次。但每次,登录程序都将使用相同的用户名和密码。所以我所有的电子邮件都无法正确登录。
如果我删除线程池,就可以了。
将您的代码更改为并尝试。您的代码正在从 lstEmailAddress 中排队,它将始终到达列表中的最后一项。更改您的代码以查询线程池中的每个项目。那应该解决。它。
for (int i = 0; i < lstEmailAddress.Count; i++)
{
ThreadPool.QueueUserWorkItem((o) =>
{
lstEmailAddress[i].IsActive = lstEmailAddress[i].Login();
}
}
你的代码很混乱:
- 如果在代码中加入
lock
,会运行同步,一次只有一个线程,会导致性能损失。
- 如果您通过
QueueUserWorkItem
排队工作 - 它将 运行 在其他线程中,并且 不在 TicketLock
中
- 您应该将锁封装在您的 class 中,而不应该在您的程序中锁定整个逻辑。
- 你开始为循环变量
i
工作,它是 being closured for it's last value,它导致你在最后一句话中陈述的问题。
lock
Email
class 中的对象不是 static
所以它是为每个实例创建的,实际上并没有锁定任何东西。
- 由于您使用的是
Invoke
方法,您的代码是从 UI 开始的,您需要传递同步上下文。我建议你使用 TPL
code for this, and do not directly work with 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;
}
}
}
}
我正在从事一个使用线程的项目。在某些情况下,我遇到了这些问题:
这是我的部分代码:
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
}));
});
}
}
}
}
这是电子邮件地址 class :
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;
}
}
}
}
我的问题是:
当我想使用属于EmailAddress
Class的Login
过程时,它有一些冲突。如您所见,我使用了 Lock
但任何东西都变了。
更多详情:
如果我在 lstEmailAddress
中有 3 个项目,则此代码必须调用登录过程 3 次。但每次,登录程序都将使用相同的用户名和密码。所以我所有的电子邮件都无法正确登录。
如果我删除线程池,就可以了。
将您的代码更改为并尝试。您的代码正在从 lstEmailAddress 中排队,它将始终到达列表中的最后一项。更改您的代码以查询线程池中的每个项目。那应该解决。它。
for (int i = 0; i < lstEmailAddress.Count; i++)
{
ThreadPool.QueueUserWorkItem((o) =>
{
lstEmailAddress[i].IsActive = lstEmailAddress[i].Login();
}
}
你的代码很混乱:
- 如果在代码中加入
lock
,会运行同步,一次只有一个线程,会导致性能损失。 - 如果您通过
QueueUserWorkItem
排队工作 - 它将 运行 在其他线程中,并且 不在TicketLock
中
- 您应该将锁封装在您的 class 中,而不应该在您的程序中锁定整个逻辑。
- 你开始为循环变量
i
工作,它是 being closured for it's last value,它导致你在最后一句话中陈述的问题。 lock
Email
class 中的对象不是static
所以它是为每个实例创建的,实际上并没有锁定任何东西。- 由于您使用的是
Invoke
方法,您的代码是从 UI 开始的,您需要传递同步上下文。我建议你使用TPL
code for this, and do not directly work withThreadPool
所以我建议你这个解决方案:
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;
}
}
}
}