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

 

posted @ 2016-07-26 13:47  码农-小菜鸟  阅读(2807)  评论(0编辑  收藏  举报