设为首页 收藏本站
查看: 587|回复: 0

[经验分享] windows服务-多线程

[复制链接]

尚未签到

发表于 2017-6-28 11:42:11 | 显示全部楼层 |阅读模式
  记录下来待以后重用,多线程windows服务
  工作项配置:


DSC0000.gif DSC0001.gif


    /// <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.ToString();
break;
case "enabled":
this.mEnabled = nvc.ToString();
break;
case "assembly":
this.mAssembly = nvc.ToString();
break;
case "interval":
this.mInterval = int.Parse(nvc.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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-388941-1-1.html 上篇帖子: 搭建 Windows Server 2012 FTP 服务器 下篇帖子: windows Nginx基本使用方法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表