Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在某些情况下,在循环条件下,线程会发生冲突_C#_Multithreading_Threadpool - Fatal编程技术网

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;
                }
            }
    
        }
    }