C# 在某些情况下,在循环条件下,线程会发生冲突
我正在从事一个使用线程的项目。在某些情况下,我会遇到以下问题: 以下是我的一些代码:C# 在某些情况下,在循环条件下,线程会发生冲突,c#,multithreading,threadpool,C#,Multithreading,Threadpool,我正在从事一个使用线程的项目。在某些情况下,我会遇到以下问题: 以下是我的一些代码: List<EmailAddress> lstEmailAddress = new List<EmailAddress>(); private void TimerCheckInternetConnection_Tick(object sender, EventArgs e) { lock (TicketLock) { if (UtilityManager.
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
类的Login
过程时,它有一些冲突。如您所见,我使用了Lock
,但任何东西都发生了变化
有关更多详细信息:如果我在
lstEmailAddress
中有3个项目,则此代码必须调用登录过程3次。但每次登录过程都使用相同的用户名和密码。所以我所有的电子邮件都无法正确登录。
如果我删除线程池,就可以了。将代码更改为,然后重试。您的代码正在从lstmailaddress中查询项目,它将始终位于该地址并点击列表中的最后一项。更改代码以查询线程池中的每个项目。这应该可以解决问题。它
for (int i = 0; i < lstEmailAddress.Count; i++)
{
ThreadPool.QueueUserWorkItem((o) =>
{
lstEmailAddress[i].IsActive = lstEmailAddress[i].Login();
}
}
for(int i=0;i
{
lstmailaddress[i].IsActive=lstmailaddress[i].Login();
}
}
您的代码非常混乱:
锁
,它将同步运行,一次只运行一个线程,这将导致性能损失QueueUserWorkItem
对工作进行排队,它将在其他线程中运行,而不在TicketLock
i
,也就是说,这会导致您在最后一句中陈述的问题lock
类中的Email
对象不是静态的
,因此它是为每个实例创建的,实际上并不锁定任何东西Invoke
方法时,您的代码是从UI启动的,您需要传递同步上下文。我建议您对此使用,不要直接使用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 lstEmailAddress=new List();
私有void timercheckineternetconnection_Tick(对象发送方,事件参数e)
{
//删除此锁,因为我们在电子邮件类中有另一个锁
//锁定(TicketLock)
if(UtilityManager.CheckForInternetConnection())
{
if(ApplicationRunStatus==Enum_ApplicationRunStatus.UnknownDisconnect
||ApplicationRunStatus==Enum_ApplicationRunStatus.IsReady)
{
for(int i=0;i
{
//如果在此处添加锁,此操作将同步运行,
//而且你并不真的需要线程池
//锁定(TicketLock)
lstEmailAddress[localIndex].IsActive=lstEmailAddress[localIndex].Login();
此.BeginInvoke(新操作(()=>
{
//一些代码
}));
});
}
}
}
}
类电子邮件地址
{
//如果您必须同时只为一个用户登录
//在这里使用静态变量,否则只需删除锁,因为它是无用的
专用静态imap客户端imap;
私有静态对象对象锁;
//仅用于静态字段的一次初始化的静态构造函数
静态电子邮件地址()
{
objectLock=新对象();
imap=新的Imap4Client();
}
公共福利活动;
公共字符串地址;
公共字符串密码;
公共字符串receiveServerAddress;
公共int接收服务器端口;
公共bool登录()
{
//获取一个静态锁
锁(对象锁)
{
尝试
{
连接SSL(ReceiveServerAddress,ReceiveServerPort);
}
捕获(例外)
{
//存储异常!!!
//返回,因为您尚未连接
返回false;
}
尝试
{
imap.Login(地址、密码);
返回true;
}
捕获(例外)
{
//存储异常!!!
返回false;
}
}
}
}
您在锁中为线程池的操作排队,但不能保证它们在您拥有锁时会执行。线程池操作需要自己锁定。因此您建议我移除锁吗?@LasseV。Karlsen@Elahe否…您应该在线程池内拉出锁。QueueUserWorkItem((o)=>{…}
block(…很可能在for
的周围,可能在BeginInvoke
中还有另一个)EmailAddress的锁不是没有用处吗?它是为EmailAddress的每个实例和锁(objectLock)创建的什么都不做?除非从另一个线程再次调用,很明显,但我不明白为什么会这样。多线程代码不仅仅是到处撒锁,您需要深入了解多线程是如何工作的,陷阱,您可以使用的工具(锁、事件、不同的集合类型等)。如果您没有,我最好的建议是不要编写多线程代码。为什么?除了提供更多需要锁的位置之外,这会有什么变化?原始代码中存在多个错误:最重要的一个错误是队列中的每个线程都能处理所有项(这在本答案中已修复)。但是,由于各地的锁定不正确,还存在其他错误。i
变量应复制到本地
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;
}
}
}
}