C# 线程函数未正确共享静态数据成员

发布于 2024-10-23 00:27:03 字数 4703 浏览 0 评论 0原文

我有一个类,如下所示

public class ScheduledUpdater
{
    private static readonly object lockingObject = new object();
    private static Queue<int> PendingIDs = new Queue<int>();
    private static bool UpdateThreadRunning = false;
    private static bool IsGetAndSaveScheduledUpdateRunning = false;
    private static DataTable ScheduleConfiguration;
    private static Thread updateRefTableThread;
    private static Thread threadToGetAndSaveScheduledUpdate;
    public static void ProcessScheduledUpdates(int ID)
    {
        //do some stuff
        // if ( updateRefTableThread not already running)
        // execute updateRefTableThread = new Thread(new ThreadStart(UpdateSchedulingRefTableInThrear));
        // execute updateRefTableThread.Start();
        //do  some stuff
        ***[1]***
        GetAndSaveScheduledUpdate(ID)
    }
    private static void UpdateSchedulingRefTableInThrear()
    {
        //if(updateRefTableThread==true)
        //    return;
        // updateRefTableThread = true
        do{
        UpdateSchedulingRefTable(); 
        Thread.sleep(800000);
        }while(updateRefTableThread);
        //updateRefTableThread = false;
    }
    public static void UpdateSchedulingRefTable()
    { 
        // read DB and update ScheduleConfiguration 
        string query = " SELECT ID,TimeToSendEmail FROM TBLa WHERE MODE = 'WebServiceOrder' AND BDELETE = false ";
        clsCommandBuilder commandBuilder = new clsCommandBuilder();
        DataSet ds = commandBuilder.GetDataSet(query);
        if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
        {
            List<string> lstIDs = new List<string>();
            for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
            {
                lstIDs.Add(ds.Tables[0].Rows[i]["ID"].ToString());
                if (LastEmailSend.Contains(ds.Tables[0].Rows[i]["ID"].ToString()))
                    LastEmailSend[ds.Tables[0].Rows[i]["ID"].ToString()] = ds.Tables[0].Rows[i]["TimeToSendEmail"].ToString();
                else
                    LastEmailSend.Add(ds.Tables[0].Rows[i]["ID"].ToString(), ds.Tables[0].Rows[i]["TimeToSendEmail"].ToString());
            }
            if (lstIDs.Count > 0)
            {
                string Ids = string.Join(",", lstIDs.ToArray()).Trim(',');
                dhDBNames dbNames = new dhDBNames();
                dbNames.Default_DB_Name = dbNames.ControlDB;
                dhGeneralPurpose dhGeneral = new dhGeneralPurpose();
                dhGeneral.StringDH = Ids;
                DataSet result = commandBuilder.GetDataSet(dbNames, (object)dhGeneral, "xmlGetConfigurations");
                if (result != null && result.Tables.Count > 0)
                {
                    ***[2]***
                    Monitor.Enter(lockingObject);
                    if (ScheduleConfiguration != null)
                        ScheduleConfiguration.Clear();
                    ScheduleConfiguration = result.Tables[0];
                    Monitor.Exit(lockingObject);
                }
            }
        }
    }
    public static void GetAndSaveScheduledUpdate(int ID)
    {
        ***[3]***
        //use ScheduleConfiguration 
        Monitor.Enter(lockingObject);
        if (ScheduleConfiguration == null)
        {
            UpdateSchedulingRefTable();
            Monitor.Exit(lockingObject);

        }
        else
            Monitor.Exit(lockingObject);
        Monitor.Enter(lockingObject);
        DataRow[] result = ScheduleConfiguration.Select("ID = "+ID);
        Monitor.Exit(lockingObject);
        //then for each result row, i add this to a static Queue PendingIDs

    }
}

函数 UpdateSchedulingRefTable 可以随时从外界调用(例如,如果有人手动更新计划配置) ProcessScheduledUpdates 每隔一分钟从 Windows 服务调用一次。 问题: 数据表 ScheduleConfigurationUpdateSchedulingRefTable 中更新(从外界调用 - 手动调用),但是当我尝试在 GetAndSaveScheduledUpdate 中使用数据表 ScheduleConfiguration,我得到了旧版本的值......

我在这个东西中缺少什么???

关于编辑:我认为我没有显示的东西是非常明显的,可能不是想要的,也许我的结构是错误的:)并且对之前的错误代码感到抱歉,我做了一个简单的函数调用作为线程初始化...抱歉对于我的代码缩进,因为我不知道如何格式化整个块...

编辑 2ProcessScheduledUpdates 是从 Windows 服务调用的(比如说每个第二)。 我首先点击点[1](它将自动点击点[2]并更新ScheduleConfiguration),然后我手动更新DB 和生命值[2]。然后我再次点击[1]来检查状态 我现在的问题是,我在 [1] 和 [2] 处获得了 ScheduleConfiguration 的两个完全不同的副本。

编辑3 我认为我的问题无效;我想在 Windows 窗体单击和 Windows 服务之间共享数据。不管我有多少共享的东西,至少地址空间会不同......我的错......

I have a class as following

public class ScheduledUpdater
{
    private static readonly object lockingObject = new object();
    private static Queue<int> PendingIDs = new Queue<int>();
    private static bool UpdateThreadRunning = false;
    private static bool IsGetAndSaveScheduledUpdateRunning = false;
    private static DataTable ScheduleConfiguration;
    private static Thread updateRefTableThread;
    private static Thread threadToGetAndSaveScheduledUpdate;
    public static void ProcessScheduledUpdates(int ID)
    {
        //do some stuff
        // if ( updateRefTableThread not already running)
        // execute updateRefTableThread = new Thread(new ThreadStart(UpdateSchedulingRefTableInThrear));
        // execute updateRefTableThread.Start();
        //do  some stuff
        ***[1]***
        GetAndSaveScheduledUpdate(ID)
    }
    private static void UpdateSchedulingRefTableInThrear()
    {
        //if(updateRefTableThread==true)
        //    return;
        // updateRefTableThread = true
        do{
        UpdateSchedulingRefTable(); 
        Thread.sleep(800000);
        }while(updateRefTableThread);
        //updateRefTableThread = false;
    }
    public static void UpdateSchedulingRefTable()
    { 
        // read DB and update ScheduleConfiguration 
        string query = " SELECT ID,TimeToSendEmail FROM TBLa WHERE MODE = 'WebServiceOrder' AND BDELETE = false ";
        clsCommandBuilder commandBuilder = new clsCommandBuilder();
        DataSet ds = commandBuilder.GetDataSet(query);
        if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
        {
            List<string> lstIDs = new List<string>();
            for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
            {
                lstIDs.Add(ds.Tables[0].Rows[i]["ID"].ToString());
                if (LastEmailSend.Contains(ds.Tables[0].Rows[i]["ID"].ToString()))
                    LastEmailSend[ds.Tables[0].Rows[i]["ID"].ToString()] = ds.Tables[0].Rows[i]["TimeToSendEmail"].ToString();
                else
                    LastEmailSend.Add(ds.Tables[0].Rows[i]["ID"].ToString(), ds.Tables[0].Rows[i]["TimeToSendEmail"].ToString());
            }
            if (lstIDs.Count > 0)
            {
                string Ids = string.Join(",", lstIDs.ToArray()).Trim(',');
                dhDBNames dbNames = new dhDBNames();
                dbNames.Default_DB_Name = dbNames.ControlDB;
                dhGeneralPurpose dhGeneral = new dhGeneralPurpose();
                dhGeneral.StringDH = Ids;
                DataSet result = commandBuilder.GetDataSet(dbNames, (object)dhGeneral, "xmlGetConfigurations");
                if (result != null && result.Tables.Count > 0)
                {
                    ***[2]***
                    Monitor.Enter(lockingObject);
                    if (ScheduleConfiguration != null)
                        ScheduleConfiguration.Clear();
                    ScheduleConfiguration = result.Tables[0];
                    Monitor.Exit(lockingObject);
                }
            }
        }
    }
    public static void GetAndSaveScheduledUpdate(int ID)
    {
        ***[3]***
        //use ScheduleConfiguration 
        Monitor.Enter(lockingObject);
        if (ScheduleConfiguration == null)
        {
            UpdateSchedulingRefTable();
            Monitor.Exit(lockingObject);

        }
        else
            Monitor.Exit(lockingObject);
        Monitor.Enter(lockingObject);
        DataRow[] result = ScheduleConfiguration.Select("ID = "+ID);
        Monitor.Exit(lockingObject);
        //then for each result row, i add this to a static Queue PendingIDs

    }
}

The function UpdateSchedulingRefTable can be called any time from outside world (for instance if someone updates the schedule configuration manually)
ProcessScheduledUpdates is called from a windows service every other minute.
Problem:
Datatable ScheduleConfiguration is updated in the UpdateSchedulingRefTable (called from outside world - say manually) but when i try to use Datatable ScheduleConfiguration in GetAndSaveScheduledUpdate, i get the older version of values....

What am I missing in this stuff???

About EDIT: I thought the stuff i have not shown is quite obvious and possibly not desired, perhaps my structure is wrong :) and sorry for incorrect code previously, i made a simple function call as a thread initialization... sorry for my code indentation too because i don't know how to format whole block...

Edit 2: ProcessScheduledUpdates is called from a windows service (say every second).
I am first hitting point [1] (it will automatically hit point [2] and update ScheduleConfiguration), then i manually update DB and hit point [2]. Then i hit point [1] again to just check the status
My problem is now, that i get two entirely different copies of ScheduleConfiguration at point [1] and [2].

Edit 3 I think my question is invalid; i wanted to share data betweena a windows form click and a windows service. No matter how many shared things i have, atleast the address space will be different... My bad...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空城之時有危險 2024-10-30 00:27:03

嗯,一方面,没有迹象表明您在任何地方都有任何内存屏障,这将确保任何写入都完全“刷新”到主内存,并且读取转到到主内存而不是使用寄存器基本上,您不应该在没有某种保护的情况下使用线程之间共享的字段。

现在,这在某种程度上是一个理论上的风险 - 目前还不清楚这是否是问题所在,尽管这确实是一种可能性。我强烈怀疑还有另一个问题,但在您没有向我们展示的代码中。您是否有诊断表明第一个线程确实写入了 ScheduleConfiguration

Well, for one thing there's no sign that you've got any memory barriers anywhere which would ensure that any writes are fully "flushed" to main memory, and that reads go to main memory instead of using registers etc. Basically you shouldn't use fields shared between threads without some sort of protection.

Now that's a theoretical risk to some extent - it's not clear that that's actually the problem, although it's certainly a real possibility. I strongly suspect there's another problem, but in the code that you haven't shown us. Do you have diagnostics to indicate that the first thread definitely wrote to ScheduleConfiguration?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文