欢迎来到陆季疵的博客

人生莫作远行客,远行莫戍黄沙碛。黄沙碛下八月时, 霜风裂肤百草衰。尘沙晴天迷道路,河水悠悠向东去。 胡笳听彻双泪流,羁魂惨惨生边愁。原头猎火夜相向, 马蹄蹴蹋层冰上。不似京华侠少年,清歌妙舞落花前。

C#进程与多线程

一、进程Process

            //获得当前程序中所有正在运行的进程
            Process[] processes = Process.GetProcesses();
            foreach (var item in processes)
            {
                //不试的不是爷们
                //item.Kill();
                Console.WriteLine(item);
            }

            //通过进程打开应用程序
            Process.Start("calc");
            Process.Start("mspaint");
            Process.Start("notepad");
            Process.Start("iexplore", "http://www.baidu.com");

            //通过进程打开指定的文件
            ProcessStartInfo psi = new ProcessStartInfo(@"C:\Users\liwen\Desktop\微信图片_20210104225821.png");
            Process process = new Process() { StartInfo = psi };
            process.Start();

 

二、线程Thread 

1、ThreadStart是一个无参的、返回值为void的委托。委托定义如下:public delegate void ThreadStart()

通过Lambda表达式创建线程

            Thread thread = new Thread(() => { Console.WriteLine("我是通过Lambda表达式创建的委托线程"); });
            thread.Start();

2、ParameterizedThreadStart是一个有参的、返回值为void的委托,定义如下:public delegate void ParameterizedThreadStart(Object obj)

            Thread thread = new Thread((e)=> { Console.WriteLine(e); });
            thread.Start("这是一个有参数的委托");

3、线程的属性与方法

            //获取正在运行的线程
            Thread thread = Thread.CurrentThread;
            //设置线程的名字
            thread.Name = "主线程";
            //获取当前线程的唯一标识符
            int id = thread.ManagedThreadId;
            //获取当前线程的状态
            ThreadState state = thread.ThreadState;
            //获取当前线程的优先级
            ThreadPriority priority = thread.Priority;
            string strMsg = string.Format("Thread ID:{0}\n" + "Thread Name:{1}\n" +
                "Thread State:{2}\n" + "Thread Priority:{3}\n", id, thread.Name,
                state, priority);

            Console.WriteLine(strMsg);

4、前台线程和后台线程-------前台线程:只有所有的前台线程都结束,应用程序才能结束。默认情况下创建的线程 都是前台线程

后台线程:只要所有的前台线程结束,后台线程自动结束。通过Thread.IsBackground设置后台线程。必须在调用Start方法之前设置线程的类型,否则一旦线程运行,将无法改变其类型。

 

        static void Main(string[] args)
        {
            //演示前台、后台线程
            BackGroundTest background = new BackGroundTest(10);
            //创建前台线程
            Thread fThread = new Thread(new ThreadStart(background.RunLoop));
            //给线程命名
            fThread.Name = "前台线程";


            BackGroundTest background1 = new BackGroundTest(20);
            //创建后台线程
            Thread bThread = new Thread(new ThreadStart(background1.RunLoop));
            bThread.Name = "后台线程";
            //设置为后台线程
            bThread.IsBackground = true;

            //启动线程
            fThread.Start();
            bThread.Start();
        }
        class BackGroundTest
        {
            private int Count;
            public BackGroundTest(int count)
            {
                this.Count = count;
            }
            public void RunLoop()
            {
                //获取当前线程的名称
                string threadName = Thread.CurrentThread.Name;
                for (int i = 0; i < Count; i++)
                {
                    Console.WriteLine("{0}计数:{1}", threadName, i.ToString());
                    //线程休眠500毫秒
                    Thread.Sleep(1000);
                }
                Console.WriteLine("{0}完成计数", threadName);

            }
        }

运行结果:前台线程执行完,后台线程未执行完,程序自动结束。把bThread.IsBackground = true注释掉,运行结果:主线程执行完毕后(Main函数),程序并未结束,而是要等所有的前台线程结束以后才会结束

后台线程一般用于处理不重要的事情,应用程序结束时,后台线程是否执行完成对整个应用程序没有影响。如果要执行的事情很重要,需要将线程设置为前台线程。

 

 

 5、线程同步-----所谓同步:是指在某一时刻只有一个线程可以访问变量。

 static void Main(string[] args)
        {
            BookShop book = new BookShop();
            //创建两个线程同时访问Sale方法
            Thread t1 = new Thread(new ThreadStart(book.Sale));
            Thread t2 = new Thread(new ThreadStart(book.Sale));
            //启动线程
            t1.Start();
            t2.Start();
            Console.ReadKey();
        }
        class BookShop
        {
            //剩余图书数量
            public int num = 1;
            public void Sale()
            {
                //使用lock关键字解决线程同步问题
                lock (this)
                {
                    int tmp = num;
                    if (tmp > 0)//判断是否有书,如果有就可以卖
                    {
                        Thread.Sleep(1000);
                        num -= 1;
                        Console.WriteLine("售出一本图书,还剩余{0}本", num);
                    }
                    else
                    {
                        Console.WriteLine("没有了");
                    }
                }
            }
        }

6、跨线程访问-----在窗体的加载事件中,将C#内置控件(Control)类的CheckForIllegalCrossThreadCalls属性设置为false,屏蔽掉C#编译器对跨线程调用的检查。

private void Form1_Load(object sender, EventArgs e)
 {
        //取消跨线程的访问
        Control.CheckForIllegalCrossThreadCalls = false;
 }

使用回调机制-----C#的方法回调机制,也是建立在委托基础上的,下面给出它的典型实现过程

        //定义回调
        private delegate void setTextValueCallBack(int value);

        public void ThreadCallBackT()
        {
            //实例化回调
           var setCallBack = new setTextValueCallBack((e) => { Console.WriteLine(e); });
            //创建一个线程去执行这个方法:创建的线程默认是前台线程
            Thread thread = new Thread(new ThreadStart(()=> 
            {
                for (int i = 0; i < 100; i++)
                {
                    //使用回调
                    setCallBack.Invoke(i);
                }
            }));
            //Start方法标记这个线程就绪了,可以随时被执行,具体什么时候执行这个线程,由CPU决定
            //将线程设置为后台线程
            thread.IsBackground = true;
            thread.Start();
        }

 二、关于线程同步

 1、文件操作的帮助类

    class TextHelper
    {
        static ReaderWriterLockSlim logLock = new ReaderWriterLockSlim();

        /// <summary>
        /// 读取文件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path"></param>
        /// <returns></returns>
        public static T ReadSerialize<T>(string path)
        {
            try
            {
                logLock.EnterReadLock();
                if (File.Exists(path))
                {
                    using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
                    {
                        BinaryFormatter formatter = new BinaryFormatter();
                        var result = formatter.Deserialize(stream);
                        stream.Close();
                        return (T)result;
                    }
                }
                return default;
            }
            catch (IOException ex)
            {
                Console.WriteLine(ex.Message);
                return default;
            }
            finally
            {
                logLock.ExitReadLock();
            }

        }
        /// <summary>
        /// 写文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="value"></param>
        public static void WriteSerialize(string path, object value)
        {
            try
            {
                logLock.EnterWriteLock();
                using (FileStream stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(stream, value);
                    stream.Close();
                }
            }
            catch (IOException ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally { logLock.ExitWriteLock(); }
        }

    }

2、序列化数据类

    [Serializable]
    class UserInfo
    {
        public string Name;
        public string Password;
        public int Age;
        public override string ToString()
        {
            return Name + "--->" + Password + "--->" + Age;
        }
    }

3、线程同步的测试

        public static void TestMethod()
        {
            string fileName = "Test.txt";

            for (int i = 1; i <= 10; i++)
            {
               var userInfo = new UserInfo()
                {
                    Name = "",
                    Age = i,
                    Password = "Pwd" + i
                };

                var task1 = Task.Factory.StartNew((obj) =>
                {
                    TextHelper.WriteSerialize(fileName, obj);
                }, userInfo);

                var task2 = Task.Factory.StartNew(() =>
                {
                    return TextHelper.ReadSerialize<UserInfo>(fileName);
                });
                Task.WaitAll(task1, task2);

                Console.WriteLine(task2.Result);
            }
            Console.Read();
        }

以上方法测试的结果不稳定,会出现多种结果

线程同步的方式-1-------下面方法可以得到想要的结果

        public static void TestMethod3()
        {
            string fileName = "Test.txt";
            for (int i = 1; i <= 10; i++)
            {
                var userInfo = new UserInfo()
                {
                    Name = "",
                    Age = i,
                    Password = "PWD" + i
                };

                Thread t0 = new Thread((info) => { TextHelper.WriteSerialize(fileName, info); });
                Thread t1 = new Thread(new ThreadStart(() => { Console.WriteLine(TextHelper.ReadSerialize<UserInfo>(fileName)); }));
                t0.Start(userInfo);
                t1.Start();
                t0.Join();
                t1.Join();
            }

            Console.Read();
        }

线程同步的方式-2-

 

 

 新建一个线程同步的帮助类

    class UserInfoHelper
    {
        //将信号状态设置为非终止状态,使用手动重置
        static EventWaitHandle myEventWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
        string fileName = "Test.txt";

        public UserInfo ReadThread()
        {
            //阻塞当前线程,直到收到信号
            myEventWaitHandle.WaitOne();
            var userInfo= TextHelper.ReadSerialize<UserInfo>(fileName);
            return userInfo;
        }

        public void WriteThread(object userInfo)
        {
            //允许其他需要等待的线程阻塞
            myEventWaitHandle.Reset();
            TextHelper.WriteSerialize(fileName, userInfo);

            //允许其他等待的线程继续
            myEventWaitHandle.Set();
        }
    }

调用方法测试

        public static void TestMethod2()
        {

            UserInfoHelper infoHelper = new UserInfoHelper();
            for (int i = 1; i <= 10; i++)
            {
                var userInfo = new UserInfo()
                {
                    Name = "",
                    Age = i,
                    Password = "PWD" + i
                };

                Thread t0 = new Thread((info) => { infoHelper.WriteThread(info); });
                Thread t1 = new Thread(new ThreadStart(() => { Console.WriteLine(infoHelper.ReadThread()); }));
                t0.Start(userInfo);
                t1.Start();

            }


            Console.Read();
        }

输出结果如下,所有写操作完成后,才逐步进行读操作;;;如果加入  t0.Join();   t1.Join();得到想要的结果

               

 

 

  线程同步的方式-3   该方式效率最高

        public static void TestMain()
        {
            UserInfoHelper infoHelper = new UserInfoHelper();
            for (int i = 1; i <= 10; i++)
            {
                var userInfo = new UserInfo()
                {
                    Name = "",
                    Age = i,
                    Password = "PWD" + i
                };

                var task1 = Task.Factory.StartNew((obj) =>
                {
                    infoHelper.WriteThread(obj);
                    Thread.Sleep(3000);
                }, userInfo);

                var task2 = Task.Factory.StartNew(() =>
                {
                    return infoHelper.ReadThread();
                });
                //Task.WaitAll(task2);//最好调用此方法进行等待,防止出错 Task.WhenAll();

                Console.WriteLine(task2.Result);
            }

            Console.ReadLine();
        }

 

 

 

一个线程的封装案列

    class ThreadHelper
    {
        public static void TestDemo()
        {
            ThreadHelper threadHelper = new ThreadHelper();
            {
                void threadStart() { Thread.Sleep(2000); Console.WriteLine("Thread第一个执行的委托方法"); };
                Action action = () => { Console.WriteLine("第二个执行的委托方法"); };
                threadHelper.ThreadWithCallBack(threadStart, action);
            }


            {
                //定义一个返回值类型为int的无参数委托,在新线程中调用
                Func<int> func = () => { Thread.Sleep(2000); return DateTime.Now.Day; };
                //将func作为参数传入扩展方法执行,并用变量接收返回的委托类型
                Func<int> funResult = threadHelper.ThreadWithReturn(func);
                //执行委托接收返回值
                int iResult = funResult.Invoke();
                Console.WriteLine(iResult);
            }
        }
        /// <summary>
        /// 扩展封装Thread
        /// </summary>
        /// <param name="threadStart">开启新线程需要执行的任务</param>
        /// <param name="actionCallback">任务执行后紧接着需要执行的任务</param>
        private void ThreadWithCallBack(ThreadStart threadStart, Action actionCallback)
        {
            ThreadStart threadStart1 = new ThreadStart(() =>
            {
                threadStart.Invoke();
                actionCallback.Invoke();
            });
            Thread thread = new Thread(threadStart1);
            thread.Start();
        }

        /// <summary>
        /// 扩展封装Thread,有返回值,需要获取结果的时候运行委托,卡界面
        /// </summary>
        /// <typeparam name="T">委托执行后的返回值</typeparam>
        /// <param name="func">开启新线程需要执行的任务</param>
        /// <returns></returns>
        private Func<T> ThreadWithReturn<T>(Func<T> func)
        {
            //指定泛型默认值
            T t = default(T);

            ThreadStart threadStart = new ThreadStart(() => { t = func.Invoke(); });
            Thread thread = new Thread(threadStart);
            thread.Start();

            return new Func<T>(() => { thread.Join(); return t; });
        }
    }

 

 

 

 

 

 

参考链接    https://www.cnblogs.com/dotnet261010/p/6159984.html

posted @ 2021-10-29 10:02  陆季疵  阅读(354)  评论(0编辑  收藏  举报
//《!--看板娘--> //https://www.cnblogs.com/ZTianming/p/14618913.html