简体   繁体   English

锁定main()线程

[英]Locking main() thread

Not exactly sure on the terminology here but here I go basically I have the main() thread of my application that starts and calls two threads, one sets up an event handler to wait for specific registry keys to change, while the other starts a timer to write any changes made to an xml file every 5 mins or so and runs continuously. 此处的术语不确定,但我基本上可以使用我的应用程序的main()线程来启动并调用两个线程,其中一个设置事件处理程序以等待特定的注册表项更改,而另一个则启动计时器每5分钟左右将对xml文件所做的任何更改写入并连续运行。 The issue I have is that once the two methods called are initialized it goes back to main and ends the program. 我的问题是,一旦调用的两个方法都初始化,它将返回到main并结束程序。 My relevant code sections can be found below, so any help would be appreciated: 我的相关代码部分可以在下面找到,所以任何帮助将不胜感激:

static void Main(string[] args)
    {
        runner one = new runner();
        runner two = new runner();

        Thread thread1 = new Thread(new ThreadStart(one.TimerMeth));
        Thread thread2 = new Thread(new ThreadStart(two.start));

        thread1.Start();
        thread2.Start();

        thread1.Join();
        thread2.Join();
    }

public void TimerMeth()
    {
        System.Timers.Timer timer = new System.Timers.Timer();

        timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);

        timer.Interval = 300000;

        timer.Enabled = true;
    }

    private void OnElapsedTime(object source, ElapsedEventArgs e)
    {
        file write = new file();
        write.write(RegKeys);
    }

public void start()
        {
            if (File.Exists("C:\\test.xml"))
            {
                file load = new file();
                RegKeys = load.read(RegKeys);
            }

            string hiveid = "HKEY_USERS";
            WindowsIdentity identity = WindowsIdentity.GetCurrent();
            string id = identity.User.ToString();

            string key1 = id + "\\\\Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Windows Messaging Subsystem\\\\Profiles\\\\Outlook\\\\0a0d020000000000c000000000000046";
            List<string> value1 = new List<String> { "01020402", "test" };

            valuechange = new RegistryValueChange(hiveid, key1, value1);
            valuechange.RegistryValueChanged += new EventHandler<RegistryValueChangedEventArgs>(valuechange_RegistryValueChanged);

            try
            {
                valuechange.Start();

            }
            catch
            {
                StreamWriter ut;
                ut = File.AppendText("C:\\test.txt");
                ut.WriteLine("error occured in starting management");
                ut.Close();
            }

            file test = new file();
            test.checkfile("C:\\test.xml");

        }

void valuechange_RegistryValueChanged(object sender, RegistryValueChangedEventArgs e)
        {
// deals with the returned values
}

Basically all the code works fine I've been testing it in a windows form application but now I need to run it in a standalone app with no interface in the background and need it to keep writing to the xml file and the change event to stay alive. 基本上所有代码都可以正常工作,我已经在Windows窗体应用程序中对其进行了测试,但是现在我需要在一个没有后台界面的独立应用程序中运行它,并且需要它继续写入xml文件和change事件,以便保留活。

Try building this into a windows service . 尝试将其构建到Windows服务中

This thread contains two suggestions for finding the logged on user from a windows service, but I am not sure if they work. 线程包含两个从Windows服务中查找登录用户的建议,但是我不确定它们是否有效。

As you can expect, the Main() method is terminating because execution flows out of the Join() methods back to the main thread, and then terminates. 如您所料, Main()方法正在终止,因为执行从Join()方法流出后又回到了主线程,然后终止。

Either place loops in the methods TimerMeth() and start() , or more appropriately redesign the application into a Windows Service (as zac says). 在方法TimerMeth()start()放置循环,或者更适当地将应用程序重新设计为Windows Service(如zac所说)。

You have a couple of issues. 您有几个问题。

Your first thread is simply creating a timer (which launches another thread). 您的第一个线程只是创建一个计时器(它将启动另一个线程)。 This thread is terminating very quickly, making your call to Join rather meaningless. 该线程很快终止,使您对Join的调用变得毫无意义。 What this thread should be doing is actually doing the waiting and the checking. 该线程应该做的实际上是在等待和检查。 You can easily adapt your code like this: 您可以像这样轻松地修改代码:

public void TimerMeth()
{
    System.Timers.Timer timer = new System.Timers.Timer();

    timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);

    timer.Interval = 300000;

    timer.Enabled = true;

    try
    {
        while(true)
        {
            OnElapsedTime(null, null); // you should change the signature

            Thread.Sleep(30000);
        }
    }
    catch(ThreadAbortException)
    {
        OnElapsedTime(null, null);

        throw;
    }
}

Obviously you should change the signature of OnElapsedTime to eliminate the parameters, since they aren't used here. 显然,您应该更改OnElapsedTime的签名以消除参数,因为此处未使用它们。

I have a feeling that something is amiss in the way that the file handling is being done, but given that I don't understand exactly what that code does , I'm going to refrain from commenting. 我感觉文件处理的方式有些问题,但是由于我不完全了解该代码的作用 ,因此我将避免发表评论。 What, exactly, is the purpose of the file? 文件的目的到底是什么? Where is RegKeys defined? RegKeys在哪里定义?

Your methods will run once, then the thread will exit. 您的方法将运行一次,然后线程将退出。 There is nothing to keep them running. 没有什么可以让它们继续运行。

Try this: 尝试这个:

thread1.IsBackground = true;
thread2.IsBackground = true;

public void start()
{
 while(true)
 {
    // ... do stuff
    Thread.Sleep(1000*60*5) // sleep for 5 minutes
 }
}

public void TimerMeth()
{
    while(true)
    {
        file write = new file();
        write.write(RegKeys);

        Thread.Sleep(30000);
    }
}

As other posters have noted, you will also then need to ensure your main method doesn't exit. 正如其他张贴者所指出的那样,您还需要确保主方法不会退出。 Making the application a windows service seems like a good way to solve this in your case. 使应用程序成为Windows服务似乎是解决此问题的好方法。

You might also want to handle ThreadInterruptedException and ThreadAbortException on your threads. 您可能还想在线程上处理ThreadInterruptedExceptionThreadAbortException

And if you really want to get into the nitty gritty of threading, check out this Free C# Threading E-Book by Joe Albahari. 如果您真的想深入了解线程的精髓,请查看Joe Albahari撰写的这本免费C#线程电子书

为了使主线程保持活动状态,最简单的方法之一是在函数的末尾添加以下行:

Thread.Sleep(Timeout.Infinite);

The Thread will terminate when your ThreadStart function returns, which allows the main thread to continue after Join() . 当您的ThreadStart函数返回时,该Thread将终止,这允许主线程在Join()之后继续。 Since you are just setting up a timer to fire off, the method will return very quickly. 由于您只是在设置要触发的计时器,因此该方法将很快返回。 You need to provide a lock of some sort to keep your application from exiting. 您需要提供某种锁,以防止应用程序退出。

Also, it doesn't look like you need to use threads at all to do what you are trying. 另外,看起来您根本不需要使用线程来完成您要尝试的工作。 Instead, just use the Timer and provide the lock to keep your Main() from terminating. 而是使用Timer并提供锁以防止Main()终止。

It looks to me like all of your functions are completing? 在我看来,您的所有功能都已完成? ie, they all "fall out the bottom". 也就是说,它们都“跌出谷底”。 Once all the functions have run through there is nothing left to do and your app will close. 一旦所有功能运行完毕,您就无事可做了,您的应用程序将关闭。 You want to run a loop of some sort in main. 您想在main中运行某种循环。

You will also need to take a look at your timer. 您还需要查看计时器。 I suspect it is currently being garbage collected. 我怀疑它目前正在被垃圾收集。 You create it in the scope of your function but that function is being left so there is no longer a reference to your timer and it will be collected. 您可以在函数范围内创建它,但是该函数已被保留,因此不再引用您的计时器,它将被收集。 Your timer needs to be a root. 您的计时器必须是root。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM