windows服務-多線程


記錄下來待以后重用,多線程windows服務

工作項配置:

    /// <summary>
    /// 工作項配置
    /// </summary>
    public abstract class ServiceConfig
    {
        #region 子類必需實現的抽象屬性

        /// <summary>
        /// 工作項說明
        /// </summary>
        public abstract string Description
        {
            get;
        }

        /// <summary>
        /// 工作項是否開啟
        /// </summary>
        public abstract string Enabled
        {
            get;
        }

        /// <summary>
        /// 工作項程序集
        /// </summary>
        public abstract string Assembly
        {
            get;
        }

        /// <summary>
        /// 工作項執行間隔時間
        /// </summary>
        public abstract int Interval
        {
            get;
        }

        #endregion

        #region 擴展屬性

        //可擴展

        #endregion
    }
View Code

工作項:

   /// <summary>
    /// 工作項
    /// </summary>
    public abstract class ServiceJob
    {
        //配置對象
        private ServiceConfig mConfigObject;
        //下次運行時間
        private DateTime mNextTime;
        //任務是否在運行中
        protected bool mIsRunning;

        /// <summary>
        /// 構造函數
        /// </summary>
        public ServiceJob()
        {
            //變量初始化
            this.mNextTime = DateTime.Now;
            this.mIsRunning = false;
        }

        /// <summary>
        /// 配置對象
        /// </summary>
        public ServiceConfig ConfigObject
        {
            get { return this.mConfigObject; }
            set { this.mConfigObject = value; }
        }

        /// <summary>
        /// 開始工作
        /// </summary>
        public void StartJob()
        {
            if (this.mConfigObject != null && this.mNextTime != null)
            {
                if (this.mConfigObject.Enabled.ToLower() == "true")
                {
                    if (DateTime.Now >= this.mNextTime)
                    {
                        if (!this.mIsRunning)
                        {
                            this.mNextTime = DateTime.Now.AddSeconds((double)this.mConfigObject.Interval);
                            this.Start();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 停止工作
        /// </summary>
        public void StopJob()
        {
            this.mConfigObject = null;
            this.mNextTime = DateTime.Now;
            this.mIsRunning = false;
            this.Stop();
        }

        #region 子類必需實現的抽象成員

        /// <summary>
        /// 開始工作
        /// </summary>
        protected abstract void Start();

        /// <summary>
        /// 停止工作
        /// </summary>
        protected abstract void Stop();

        #endregion
    }
View Code

工具類:

 /// <summary>
    /// 工具類
    /// </summary>
    public class ServiceTools : System.Configuration.IConfigurationSectionHandler
    {
        /// <summary>
        /// 獲取AppSettings節點值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetAppSetting(string key)
        {
            return ConfigurationManager.AppSettings[key].ToString();
        }

        /// <summary>
        /// 獲取configSections節點
        /// </summary>
        /// <returns></returns>
        public static XmlNode GetConfigSections()
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath);
            return doc.DocumentElement.FirstChild;
        }

        /// <summary>
        /// 獲取section節點
        /// </summary>
        /// <param name="nodeName"></param>
        /// <returns></returns>
        public static NameValueCollection GetSection(string nodeName)
        {
            return (NameValueCollection)ConfigurationManager.GetSection(nodeName);
        }

        /// <summary>
        /// 停止Windows服務
        /// </summary>
        /// <param name="serviceName">服務名稱</param>
        public static void WindowsServiceStop(string serviceName)
        {
            System.ServiceProcess.ServiceController control = new System.ServiceProcess.ServiceController(serviceName);
            control.Stop();
            control.Dispose();
        }

        /// <summary>
        /// 寫日志
        /// </summary>
        /// <param name="path">日志文件</param>
        /// <param name="cont">日志內容</param>
        /// <param name="isAppend">是否追加方式</param>
        public static void WriteLog(string path, string cont, bool isAppend)
        {
            using (StreamWriter sw = new StreamWriter(path, isAppend, System.Text.Encoding.UTF8))
            {
                sw.WriteLine(DateTime.Now);
                sw.WriteLine(cont);
                sw.WriteLine("");
                sw.Close();
            }
        }

        /// <summary>
        /// 實現接口以讀寫app.config
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="configContext"></param>
        /// <param name="section"></param>
        /// <returns></returns>
        public object Create(object parent, object configContext, System.Xml.XmlNode section)
        {
            System.Configuration.NameValueSectionHandler handler = new System.Configuration.NameValueSectionHandler();
            return handler.Create(parent, configContext, section);
        }

    }
View Code

Service:

public partial class Service1 : ServiceBase
    {
        //用哈希表存放任務項
        private Hashtable hashJobs;

        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            WriteLog.WriteMessage("Info", "runJobs_啟動服務_" + DateTime.Now.ToString());
            //啟動服務
            this.runJobs();
        }

        protected override void OnStop()
        {
            WriteLog.WriteMessage("Info", "stopJobs_停止服務_" + DateTime.Now.ToString());
            //停止服務
            this.stopJobs();
        }

        #region 自定義方法

        private void runJobs()
        {
            try
            {
                WriteLog.WriteMessage("Info", "runJobs_加載工作項_" + DateTime.Now.ToString());
                //加載工作項
                if (this.hashJobs == null)
                {
                    hashJobs = new Hashtable();

                    //獲取configSections節點
                    XmlNode configSections = Base.ServiceTools.GetConfigSections();
                    foreach (XmlNode section in configSections)
                    {
                        //過濾注釋節點(如section中還包含其它節點需過濾)
                        if (section.Name.ToLower() == "section")
                        {
                            //創建每個節點的配置對象
                            string sectionName = section.Attributes["name"].Value.Trim();
                            string sectionType = section.Attributes["type"].Value.Trim();

                            //程序集名稱
                            string assemblyName = sectionType.Split(',')[1];
                            //完整類名
                            string classFullName = assemblyName + ".Jobs." + sectionName + ".Config";

                            //創建配置對象
                            Base.ServiceConfig config = (Base.ServiceConfig)Assembly.Load(assemblyName).CreateInstance(classFullName);
                            //創建工作對象
                            Base.ServiceJob job = (Base.ServiceJob)Assembly.Load(config.Assembly.Split(',')[1]).CreateInstance(config.Assembly.Split(',')[0]);
                            job.ConfigObject = config;

                            //將工作對象加載進HashTable
                            this.hashJobs.Add(sectionName, job);
                        }
                    }
                }
                WriteLog.WriteMessage("Info", "runJobs_執行工作項_" + DateTime.Now.ToString() + "  hashJobs.Keys.Count:" + this.hashJobs.Keys.Count);
                //執行工作項
                if (this.hashJobs.Keys.Count > 0)
                {
                    foreach (Base.ServiceJob job in hashJobs.Values)
                    {
                        //插入一個新的請求到線程池
                        if (System.Threading.ThreadPool.QueueUserWorkItem(threadCallBack, job))
                        {
                            //方法成功排入隊列
                            WriteLog.WriteMessage("Info", "runJobs_方法成功排入隊列_" + DateTime.Now.ToString() + "  Description:" + job.ConfigObject.Description);
                        }
                        else
                        {
                            //方法排入隊列失敗
                            WriteLog.WriteMessage("Info", "runJobs_方法排入隊列失敗_" + DateTime.Now.ToString() + "  Description:" + job.ConfigObject.Description);
                        }
                    }
                }
            }
            catch (Exception error)
            {
                WriteLog.WriteErorrLog("Error", error);
            }
        }

        private void stopJobs()
        {
            //停止
            if (this.hashJobs != null)
            {
                this.hashJobs.Clear();
            }
        }

        /// <summary>
        /// 線程池回調方法
        /// </summary>
        /// <param name="state"></param>
        private void threadCallBack(Object state)
        {
            while (true)
            {
                ((Base.ServiceJob)state).StartJob();
                //休眠1秒
                Thread.Sleep(1000);
            }
        }

        #endregion

    }
View Code

AppConfig:

 <configSections>
    <!--自定義工作項,name屬性請與Jobs下的任務目錄同名,會據此加載該任務的config對象-->
    <section name="JobIndustry" type="SouMaiService.Base.ServiceTools,SouMaiService"/>
    <section name="JobKey" type="SouMaiService.Base.ServiceTools,SouMaiService"/>
    </configSections>

<JobKey>
    <add key="description" value="關鍵字緩存"/>
    <add key="enabled" value="true"/>
    <add key="assembly" value="SouMaiService.Jobs.JobKey.Job,SouMaiService"/>
    <add key="interval" value="345600000"/>
  </JobKey>

  <appSettings>
    <!--每個線程操作緩存的數據量  -->
    <add key="ThreadMaxCount" value="30000"/>
    <!--JobKey 線程的起始值 1 -->
    <add key="JobKeyStartID" value="2600000"/>
    <!--JobKey 線程的最大值 當此值為空值時 則表示不配置線程最大值 -->
    <add key="JobKeyEndID" value="2900000"/>
  </appSettings>
View Code

應用程序的主入口點:

    static class Program
    {
        /// <summary>
        /// 應用程序的主入口點。
        /// </summary>
        static void Main()
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] 
            { 
                new Service1() 
            };
            ServiceBase.Run(ServicesToRun);
        }
    }
View Code

WriteLog日志:

public class WriteLog
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="ex"></param>
        public static void WriteErorrLog(string fileName, Exception ex)
        {
            if (ex == null) return; //ex = null 返回  
            DateTime dt = DateTime.Now; // 設置日志時間  
            string time = dt.ToString("yyyy-MM-dd HH:mm:ss"); //年-月-日 時:分:秒  
            string logName = dt.ToString("yyyy-MM-dd"); //日志名稱  
            string logPath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, Path.Combine("log", fileName)); //日志存放路徑  
            string log = Path.Combine(logPath, string.Format("{0}.log", logName)); //路徑 + 名稱
            try
            {
                FileInfo info = new FileInfo(log);
                if (info.Directory != null && !info.Directory.Exists)
                {
                    info.Directory.Create();
                }
                using (StreamWriter write = new StreamWriter(log, true, Encoding.GetEncoding("utf-8")))
                {
                    write.WriteLine(time);
                    write.WriteLine(ex.Message);
                    write.WriteLine("異常信息:" + ex);
                    write.WriteLine("異常堆棧:" + ex.StackTrace);
                    write.WriteLine("異常簡述:" + ex.Message);
                    write.WriteLine("\r\n----------------------------------\r\n");
                    write.Flush();
                    write.Close();
                    write.Dispose();
                }
            }
            catch { }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="message"></param>
        public static void WriteMessage(string fileName, string message)
        {
            //ex = null 返回  
            DateTime dt = DateTime.Now; // 設置日志時間  
            string time = dt.ToString("yyyy-MM-dd HH:mm:ss"); //年-月-日 時:分:秒  
            string logName = dt.ToString("yyyy-MM-dd"); //日志名稱  
            string logPath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, Path.Combine("log", fileName)); //日志存放路徑  
            string log = Path.Combine(logPath, string.Format("{0}.log", logName)); //路徑 + 名稱
            try
            {
                FileInfo info = new FileInfo(log);
                if (info.Directory != null && !info.Directory.Exists)
                {
                    info.Directory.Create();
                }
                using (StreamWriter write = new StreamWriter(log, true, Encoding.GetEncoding("utf-8")))
                {
                    write.WriteLine(time);
                    write.WriteLine("信息:" + message);
                    write.WriteLine("\r\n----------------------------------\r\n");
                    write.Flush();
                    write.Close();
                    write.Dispose();
                }
            }
            catch { }
        }


        public static void WriteErorrLog(Exception ex, string message)
        {
            if (ex == null) return; //ex = null 返回  
            DateTime dt = DateTime.Now; // 設置日志時間  
            string time = dt.ToString("yyyy-MM-dd HH:mm:ss"); //年-月-日 時:分:秒  
            string logName = dt.ToString("yyyy-MM-dd"); //日志名稱  
            string logPath = System.AppDomain.CurrentDomain.BaseDirectory; //日志存放路徑  
            string log = Path.Combine(Path.Combine(logPath, "log"), string.Format("{0}.log", logName)); //路徑 + 名稱
            try
            {
                FileInfo info = new FileInfo(log);
                if (info.Directory != null && !info.Directory.Exists)
                {
                    info.Directory.Create();
                }
                using (StreamWriter write = new StreamWriter(log, true, Encoding.GetEncoding("utf-8")))
                {
                    write.WriteLine(time);
                    write.WriteLine(ex.Message);
                    write.WriteLine("異常信息:" + ex);
                    write.WriteLine("異常堆棧:" + ex.StackTrace);
                    write.WriteLine("異常簡述:" + message);
                    write.WriteLine("\r\n----------------------------------\r\n");
                    write.Flush();
                    write.Close();
                    write.Dispose();
                }
            }
            catch { }
        }

        public static void WriteMessage(string message)
        {
            //ex = null 返回  
            DateTime dt = DateTime.Now; // 設置日志時間  
            string time = dt.ToString("yyyy-MM-dd HH:mm:ss"); //年-月-日 時:分:秒  
            string logName = dt.ToString("yyyy-MM-dd"); //日志名稱  
            string logPath = System.AppDomain.CurrentDomain.BaseDirectory; //日志存放路徑  
            string log = Path.Combine(Path.Combine(logPath, "log"), string.Format("{0}.log", logName)); //路徑 + 名稱
            try
            {
                FileInfo info = new FileInfo(log);
                if (info.Directory != null && !info.Directory.Exists)
                {
                    info.Directory.Create();
                }
                using (StreamWriter write = new StreamWriter(log, true, Encoding.GetEncoding("utf-8")))
                {
                    write.WriteLine(time);
                    write.WriteLine("信息:" + message);
                    write.WriteLine("\r\n----------------------------------\r\n");
                    write.Flush();
                    write.Close();
                    write.Dispose();
                }
            }
            catch { }
        }
    }
View Code

 線程使用:

namespace SouMaiService.Jobs.JobKey
{
    public class Config : Base.ServiceConfig
    {
        #region 基本屬性

        private string mDescription;
        private string mEnabled;
        private string mAssembly;
        private int mInterval;

        /// <summary>
        /// 說明
        /// </summary>
        public override string Description
        {
            get { return this.mDescription; }
        }

        /// <summary>
        /// 是否開啟
        /// </summary>
        public override string Enabled
        {
            get { return this.mEnabled; }
        }

        /// <summary>
        /// 處理程序集
        /// </summary>
        public override string Assembly
        {
            get { return this.mAssembly; }
        }

        /// <summary>
        /// 間隔時間
        /// </summary>
        public override int Interval
        {
            get { return this.mInterval; }
        }

        #endregion

        #region 構造函數

        /// <summary>
        /// 構造函數,將配置項加載進對象
        /// </summary>
        public Config()
        {
            NameValueCollection nvc = Base.ServiceTools.GetSection("JobKey");

            foreach (string s in nvc.Keys)
            {
                switch (s.ToLower())
                {
                    //基本
                    case "description":
                        this.mDescription = nvc[s].ToString();
                        break;
                    case "enabled":
                        this.mEnabled = nvc[s].ToString();
                        break;
                    case "assembly":
                        this.mAssembly = nvc[s].ToString();
                        break;
                    case "interval":
                        this.mInterval = int.Parse(nvc[s].ToString());
                        break;
                }
            }
        }

        #endregion

    }
}
View Code
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace SouMaiService.Jobs.JobKey
{
    public class Job : Base.ServiceJob
    {
        /// <summary>
        /// 任務開始
        /// </summary>
        protected override void Start()
        {
            try
            {
                //運行中
                this.mIsRunning = true;
                //執行工作項
                this.executeLogic();
            }
            catch (Exception error)
            {
                //異常日志
                WriteLog.WriteErorrLog("JobKey" + DateTime.Now.ToString("yyyy_MM_dd"), error);

                //發生異常時停止服務程序
                Base.ServiceTools.WindowsServiceStop("SouMaiService");
            }
            finally
            {
                //空閑
                this.mIsRunning = false;
            }
        }

        /// <summary>
        /// 任務停止
        /// </summary>
        protected override void Stop()
        {
            this.mIsRunning = false;
        }

        /// <summary>
        /// 執行邏輯
        /// </summary>
        private void executeLogic()
        {
            InsertRedis bll = new InsertRedis();

            int minKeyID = int.Parse(Base.ServiceTools.GetAppSetting("JobKeyStartID"));//起始ID
            int count = 0;
            //因數據可被刪除 所以需要取出來最大的 KeyID - 起始值
            count = bll.GetMaxKeyId() - minKeyID;
            //count = bll.GetKeyCount();

            //每次線程緩存的數據間隔最大值
            int maxCount = int.Parse(Base.ServiceTools.GetAppSetting("ThreadMaxCount"));
            //向上取整 
            int num = int.Parse(Math.Ceiling((double)count / (double)maxCount).ToString());


            int preNum = minKeyID;
            for (int i = 1; i <= num; i++)
            {
                object ids = preNum.ToString() + "^" + (preNum + maxCount).ToString();
                //線程池
                System.Threading.ThreadPool.QueueUserWorkItem(SetKeyRedis, ids);
                //bll.SetKeyRedis(preNum, preNum + maxCount);
                preNum = preNum + maxCount;
            }
        }

        private void SetKeyRedis(object ids)
        {
            InsertRedis bll = new InsertRedis();
            int beginId = int.Parse(ids.ToString().Split('^')[0]);
            int endId = int.Parse(ids.ToString().Split('^')[1]);
            bll.SetKeyRedis(beginId, endId);
        }

    }
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM