Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等

以上介绍是从博客园张善友(http://www.cnblogs.com/shanyou/archive/2007/08/25/quartznettutorial.html)的博客摘录,可登录他博客具体了解quartz.net。

我在这里只讲具体在项目中的实现:

通过Windows服务调用Quartz.net,然后Quartz.net 调用WinForm消息窗口,实现计划任务消息推送。

【Windows服务】-->【Quartz.net】 --> 【Winform .exe】 --> 【程序打包】


项目解决方案,如图所示:

一、创建Windows服务


1、打开vs2010--新建项目--选择"Windows服务",我这里命名为"QuartzService". 创建好后首先映入我们眼帘的是QuartzService.cs[设计]视图,右键点设计视图选择"添加安装程序",如下图:

注释:(创建一个Windows服务,仅用InstallUtil程序去安装这个服务是不够的。你必须还要把一个服务安装程序添加到你的Windows服务当中,这样便于InstallUtil或是任何别的安装程序知道应用你服务的是怎样的配置设置)

2、切换到刚被添加的ProjectInstaller的设计视图, 设置serviceInstaller1组件的属性: StartType = Automatic;ServiceName = QuartzService;

设置serviceProcessInstaller1组件的属性 Account = LocalSystem; 如下图:

3、QuartzService中添加Quartz.dll ,log4net.dll引用,在QuartzService.cs文件中引用命名空间 Quartz;Quartz.Impl; log4net;

右键点击QuartzService项目,属性-目标框架 ,选择.net Framwork 4,如下图:

4、添加app.config配置文件,具体配置如下:

 1 <?xml version="1.0"?>
 2 <configuration>
 3   <configSections>
 4     <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
 5     <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
 6     <sectionGroup name="common">
 7       <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
 8     </sectionGroup>
 9   </configSections>
10   <common>
11     <logging>
12       <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net">
13         <arg key="configType" value="INLINE"/>
14       </factoryAdapter>
15     </logging>
16   </common>
17   <log4net>
18     <appender name="InfoFileAppender" type="log4net.Appender.RollingFileAppender">
19       <file value="log/" />
20       <appendToFile value="true" />
21       <param name="DatePattern" value="yyyyMMdd&quot;.txt&quot;" />
22       <rollingStyle value="Date" />
23       <maxSizeRollBackups value="100" />
24       <maximumFileSize value="1024KB" />
25       <staticLogFileName value="false" />
26       <Encoding value="UTF-8" />
27       <filter type="log4net.Filter.LevelRangeFilter">
28         <param name="LevelMin" value="INFO" />
29         <param name="LevelMax" value="INFO" />
30       </filter>
31       <layout type="log4net.Layout.PatternLayout">
32         <conversionPattern value="%date %-5level %logger  - %message%newline" />
33       </layout>
34     </appender>
35     <appender name="ErrorFileAppender" type="log4net.Appender.RollingFileAppender">
36       <file value="log/error.txt" />
37       <appendToFile value="true" />
38       <rollingStyle value="Size" />
39       <maxSizeRollBackups value="100" />
40       <maximumFileSize value="10240KB" />
41       <staticLogFileName value="true" />
42       <Encoding value="UTF-8" />
43       <filter type="log4net.Filter.LevelRangeFilter">
44         <param name="LevelMin" value="WARN" />
45         <param name="LevelMax" value="FATAL" />
46       </filter>
47       <layout type="log4net.Layout.PatternLayout">
48         <conversionPattern value="%date %-5level %logger - %message%newline" />
49       </layout>
50     </appender>
51     <root>
52       <level value="INFO" />
53       <appender-ref ref="InfoFileAppender" />
54       <appender-ref ref="ErrorFileAppender" />
55     </root>
56   </log4net>
57
58   <!--
59     We use quartz.config for this server, you can always use configuration section if you want to.
60     Configuration section has precedence here.
61   -->
62   <appSettings>
63     <!-- YYC.WebService URL地址 -->
64     <add key="URL" value="http://localhost:43093/WebService.asmx" />
65   </appSettings>
66   <!--
67   <quartz >
68   </quartz>
69   -->
70   <startup>
71     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
72   </startup>
73 </configuration>

View Code

二、创建Quartz.Net.JobLibrary并配置Job


1、在解决方案中添加新项-选择"类库",我这里命名为Quartz.Net.JobLibrary,Quartz.Net.JobLibrary用来实现多个"作业"类。Quartz.Net.JobLibrary类库中添加Quartz.dll ,log4net.dll引用。

Quartz.Net.JobLibrary类库中添加一个类Interop.cs,这个类是为了解决在Win7中出现【交互式检测】弹窗,博客园李敬然(http://www.cnblogs.com/gnielee/archive/2010/04/07/session0-isolation-part1.html)的博客详细谈到 穿透Session 0 隔离,具体代码如下:

  1 using System;
  2 using System.Runtime.InteropServices;
  3
  4 namespace Quartz.Net.JobLibrary
  5 {
  6     public class Interop
  7     {
  8         public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
  9         public static void ShowMessageBox(string message, string title)
 10         {
 11             int resp = 0;
 12             WTSSendMessage(
 13                 WTS_CURRENT_SERVER_HANDLE,
 14                 WTSGetActiveConsoleSessionId(),
 15                 title, title.Length,
 16                 message, message.Length,
 17                 0, 0, out resp, false);
 18         }
 19         [DllImport("kernel32.dll", SetLastError = true)]
 20         public static extern int WTSGetActiveConsoleSessionId();
 21         [DllImport("wtsapi32.dll", SetLastError = true)]
 22         public static extern bool WTSSendMessage(
 23             IntPtr hServer,
 24             int SessionId,
 25             String pTitle,
 26             int TitleLength,
 27             String pMessage,
 28             int MessageLength,
 29             int Style,
 30             int Timeout,
 31             out int pResponse,
 32             bool bWait);
 33
 34         public static void CreateProcess(string app, string path)
 35         {
 36             IntPtr hToken;
 37             IntPtr hDupedToken = IntPtr.Zero;
 38
 39             PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
 40             SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
 41             sa.Length = Marshal.SizeOf(sa);
 42
 43             STARTUPINFO si = new STARTUPINFO();
 44             si.cb = Marshal.SizeOf(si);
 45
 46             int dwSessionID = WTSGetActiveConsoleSessionId();
 47             bool result = WTSQueryUserToken(dwSessionID, out hToken);
 48
 49             if (!result)
 50             {
 51                 ShowMessageBox("WTSQueryUserToken failed", "AlertService Message");
 52             }
 53
 54             result = DuplicateTokenEx(
 55                   hToken,
 56                   GENERIC_ALL_ACCESS,
 57                   ref sa,
 58                   (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
 59                   (int)TOKEN_TYPE.TokenPrimary,
 60                   ref hDupedToken
 61                );
 62
 63             if (!result)
 64             {
 65                 ShowMessageBox("DuplicateTokenEx failed", "AlertService Message");
 66             }
 67
 68             IntPtr lpEnvironment;
 69             result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);
 70
 71             if (!result)
 72             {
 73                 ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message");
 74             }
 75
 76             result = CreateProcessAsUser(
 77                         hDupedToken,
 78                         path + app,
 79                         String.Empty,
 80                         ref sa, ref sa,
 81                         false, 0, IntPtr.Zero,
 82                         path, ref si, ref pi);
 83
 84             if (!result)
 85             {
 86                 int error = Marshal.GetLastWin32Error();
 87                 string message = String.Format("CreateProcessAsUser Error: {0}", error);
 88                 ShowMessageBox(message, "AlertService Message");
 89             }
 90
 91             if (pi.hProcess != IntPtr.Zero)
 92                 CloseHandle(pi.hProcess);
 93             if (pi.hThread != IntPtr.Zero)
 94                 CloseHandle(pi.hThread);
 95             if (hDupedToken != IntPtr.Zero)
 96                 CloseHandle(hDupedToken);
 97         }
 98
 99         [StructLayout(LayoutKind.Sequential)]
100         public struct STARTUPINFO
101         {
102             public Int32 cb;
103             public string lpReserved;
104             public string lpDesktop;
105             public string lpTitle;
106             public Int32 dwX;
107             public Int32 dwY;
108             public Int32 dwXSize;
109             public Int32 dwXCountChars;
110             public Int32 dwYCountChars;
111             public Int32 dwFillAttribute;
112             public Int32 dwFlags;
113             public Int16 wShowWindow;
114             public Int16 cbReserved2;
115             public IntPtr lpReserved2;
116             public IntPtr hStdInput;
117             public IntPtr hStdOutput;
118             public IntPtr hStdError;
119         }
120
121         [StructLayout(LayoutKind.Sequential)]
122         public struct PROCESS_INFORMATION
123         {
124             public IntPtr hProcess;
125             public IntPtr hThread;
126             public Int32 dwProcessID;
127             public Int32 dwThreadID;
128         }
129
130         [StructLayout(LayoutKind.Sequential)]
131         public struct SECURITY_ATTRIBUTES
132         {
133             public Int32 Length;
134             public IntPtr lpSecurityDescriptor;
135             public bool bInheritHandle;
136         }
137
138         public enum SECURITY_IMPERSONATION_LEVEL
139         {
140             SecurityAnonymous,
141             SecurityIdentification,
142             SecurityImpersonation,
143             SecurityDelegation
144         }
145
146         public enum TOKEN_TYPE
147         {
148             TokenPrimary = 1,
149             TokenImpersonation
150         }
151
152         public const int GENERIC_ALL_ACCESS = 0x10000000;
153
154         [DllImport("kernel32.dll", SetLastError = true,
155             CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
156         public static extern bool CloseHandle(IntPtr handle);
157
158         [DllImport("advapi32.dll", SetLastError = true,
159             CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
160         public static extern bool CreateProcessAsUser(
161             IntPtr hToken,
162             string lpApplicationName,
163             string lpCommandLine,
164             ref SECURITY_ATTRIBUTES lpProcessAttributes,
165             ref SECURITY_ATTRIBUTES lpThreadAttributes,
166             bool bInheritHandle,
167             Int32 dwCreationFlags,
168             IntPtr lpEnvrionment,
169             string lpCurrentDirectory,
170             ref STARTUPINFO lpStartupInfo,
171             ref PROCESS_INFORMATION lpProcessInformation);
172
173         [DllImport("advapi32.dll", SetLastError = true)]
174         public static extern bool DuplicateTokenEx(
175             IntPtr hExistingToken,
176             Int32 dwDesiredAccess,
177             ref SECURITY_ATTRIBUTES lpThreadAttributes,
178             Int32 ImpersonationLevel,
179             Int32 dwTokenType,
180             ref IntPtr phNewToken);
181
182         [DllImport("wtsapi32.dll", SetLastError = true)]
183         public static extern bool WTSQueryUserToken(
184             Int32 sessionId,
185             out IntPtr Token);
186
187         [DllImport("userenv.dll", SetLastError = true)]
188         static extern bool CreateEnvironmentBlock(
189             out IntPtr lpEnvironment,
190             IntPtr hToken,
191             bool bInherit);
192     }
193 }

View Code

Quartz.Net.JobLibrary类库中再分别添加两个"作业"类JobTest1.cs,JobTest2.cs:

代码如下

JobTest1.cs

 1 using System;
 2 using System.Configuration;
 3 using System.Reflection;
 4 using Common.Logging;
 5
 6 namespace Quartz.Net.JobLibrary
 7 {
 8     public class JobTest1 : IJob
 9     {
10         //使用Common.Logging.dll日志接口实现日志记录
11         private static readonly ILog logger =
12             LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
13
14         private static string URL = ConfigurationManager.AppSettings["URL"];
15
16         #region IJob 成员
17
18         public void Execute(IJobExecutionContext context)
19         {
20             try
21             {
22                 logger.Info("JobTest1 任务开始运行");
23                 //ShowMsgBox msgBox = new ShowMsgBox();
24                 //msgBox.ShowMsg(100, "AAAA", "计划任务提醒");
25                 //WebServiceSoapClient client = new WebServiceSoapClient(new BasicHttpBinding(), new EndpointAddress(URL));
26                 //client.Shake();
27                 //ShowMsg(100, "AAAA", "计划任务提醒");
28                 //Interop.ShowMessageBox("This a message from AlertService.",
29                 //          "AlertService Message");
30                 string path = System.Windows.Forms.Application.StartupPath;
31                 Interop.CreateProcess("Quartz.Net.WinForm.exe", path + "\\");
32                 logger.Info("JobTest1 任务运行结束");
33             }
34             catch (Exception ex)
35             {
36                 logger.Error("JobTest1 运行异常", ex);
37             }
38         }
39
40         #endregion
41
42     }
43 }

View Code

2、在Quartz.Net.JobLibrary中,添加配置文件quartz_jobs.xml,配置信息如下:

  1 <?xml version="1.0" encoding="UTF-8"?>
  2
  3 <!-- This file contains job definitions in schema version 2.0 format -->
  4 <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
  5   <processing-directives>
  6     <overwrite-existing-data>true</overwrite-existing-data>
  7   </processing-directives>
  8
  9   <schedule>
 10     <!--定义JobTest1-->
 11     <job>
 12       <name>JobTest1</name>
 13       <group>JobGroup</group>
 14       <description>测试任务1</description>
 15       <job-type>Quartz.Net.JobLibrary.JobTest1,Quartz.Net.JobLibrary</job-type>
 16       <durable>true</durable>
 17       <recover>false</recover>
 18     </job>
 19
 20     <!--定义示JobTest2-->
 21     <job>
 22       <name>JobTest2</name>
 23       <group>JobGroup</group>
 24       <description>测试任务2</description>
 25       <job-type>Quartz.Net.JobLibrary.JobTest2,Quartz.Net.JobLibrary</job-type>
 26       <durable>true</durable>
 27       <recover>false</recover>
 28     </job>
 29
 30     <!--定义JobTest1 触发器 每30秒执行一次任务-->
 31     <trigger>
 32       <cron>
 33         <name>JobTestTrigger1</name>
 34         <group>TriggerGroup</group>
 35         <job-name>JobTest1</job-name>
 36         <job-group>JobGroup</job-group>
 37         <cron-expression>0/30 * * * * ?</cron-expression>
 38       </cron>
 39     </trigger>
 40
 41     <!--定义JobTest2 触发器 每分钟执行一次任务-->
 42     <trigger>
 43       <cron>
 44         <name>JobTestTrigger2</name>
 45         <group>TriggerGroup</group>
 46         <job-name>JobTest2</job-name>
 47         <job-group>JobGroup</job-group>
 48         <cron-expression>0 * * * * ?</cron-expression>
 49       </cron>
 50     </trigger>
 51
 52     <!--定义JobTest2 触发器 每天凌晨01:00执行一次任务-->
 53     <trigger>
 54       <cron>
 55         <name>JobTestTrigger3</name>
 56         <group>TriggerGroup</group>
 57         <job-name>JobTest2</job-name>
 58         <job-group>JobGroup</job-group>
 59         <cron-expression>0 0 1 * * ?</cron-expression>
 60       </cron>
 61     </trigger>
 62   </schedule>
 63
 64 <!-- Cron Expressions——Cron 表达式
 65       Cron表达式被用来配置CronTrigger实例。Cron表达式是一个由7个子表达式组成的字符串。每个子表达式都描述了一个单独的日程细节。这些子表达式用空格分隔,分别表示:
 66       1. Seconds 秒
 67       2. Minutes 分钟
 68       3. Hours 小时
 69       4. Day-of-Month 月中的天
 70       5. Month 月
 71       6. Day-of-Week 周中的天
 72       7. Year (optional field) 年(可选的域)
 73       一个cron表达式的例子字符串为"0 0 12 ? * WED",这表示“每周三的中午12:00”。
 74       单个子表达式可以包含范围或者列表。例如:前面例子中的周中的天这个域(这里是"WED")可以被替换为"MON-FRI", "MON, WED, FRI"或者甚至"MON-WED,SAT"。
 75       通配符('*')可以被用来表示域中“每个”可能的值。因此在"Month"域中的*表示每个月,而在Day-Of-Week域中的*则表示“周中的每一天”。
 76       所有的域中的值都有特定的合法范围,这些值的合法范围相当明显,例如:秒和分域的合法值为0到59,小时的合法范围是0到23,Day-of-Month中值得合法凡范围是0到31,
 77       但是需要注意不同的月份中的天数不同。月份的合法值是0到11。或者用字符串JAN,FEB MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV 及DEC来表示。
 78       Days-of-Week可以用1到7来表示(1=星期日)或者用字符串SUN, MON, TUE, WED, THU, FRI 和SAT来表示.
 79       '/'字符用来表示值的增量,例如, 如果分钟域中放入'0/15',它表示“每隔15分钟,从0开始”,如果在份中域中使用'3/20',则表示“小时中每隔20分钟,
 80       从第3分钟开始”或者另外相同的形式就是'3,23,43'。
 81       '?'字符可以用在day-of-month及day-of-week域中,它用来表示“没有指定值”。这对于需要指定一个或者两个域的值而不需要对其他域进行设置来说相当有用。
 82       'L'字符可以在day-of-month及day-of-week中使用,这个字符是"last"的简写,但是在两个域中的意义不同。例如,在day-of-month域中的"L"表示这个月的最后一天,
 83       即,一月的31日,非闰年的二月的28日。如果它用在day-of-week中,则表示"7"或者"SAT"。但是如果在day-of-week域中,这个字符跟在别的值后面,
 84       则表示"当月的最后的周XXX"。例如:"6L" 或者 "FRIL"都表示本月的最后一个周五。当使用'L'选项时,最重要的是不要指定列表或者值范围,否则会导致混乱。
 85       'W' 字符用来指定距离给定日最接近的周几(在day-of-week域中指定)。例如:如果你为day-of-month域指定为"15W",则表示“距离月中15号最近的周几”。
 86       '#'表示表示月中的第几个周几。例如:day-of-week域中的"6#3" 或者 "FRI#3"表示“月中第三个周五”。
 87       下面是一些表达式以及它们的含义。
 88       Example Cron Expressions ——Cron表达式的例子
 89       CronTrigger
 90       例1 – 一个简单的每隔5分钟触发一次的表达式
 91       "0 0/5 * * * ?" CronTrigger
 92        例2 – 在每分钟的10秒后每隔5分钟触发一次的表达式(例如. 10:00:10 am, 10:05:10等.)。
 93       "10 0/5 * * * ?" CronTrigger
 94       例3 – 在每个周三和周五的10:30,11:30,12:30触发的表达式。
 95       "0 30 10-13 ? * WED,FRI" CronTrigger
 96       例4 – 在每个月的5号,20号的8点和10点之间每隔半个小时触发一次且不包括10点,只是8:30,9:00和9:30的表达式。
 97       "0 0/30 8-9 5,20 * ?" 注意,对于单独触发器来说,有些日程需求可能过于复杂而不能用表达式表述,例如:9:00到10:00之间每隔5分钟触发一次,
 98       下午1:00到10点每隔20分钟触发一次。这个解决方案就是创建两个触发器,两个触发器都运行相同的任务。
 99 -->
100 </job-scheduling-data>

View Code

三、创建Quartz.Net.WinForm消息窗口


1、在解决方案中添加新项-选择"windows 应用程序",我这里命名为Quartz.Net.WinForm,具体实现从右下角逐渐显示气泡式窗口如图所示:

点击【确定】从右下角逐渐消失

通过JobTest1调用消息窗口,

string path = System.Windows.Forms.Application.StartupPath;
Interop.CreateProcess("Quartz.Net.WinForm.exe", path + "\\");

实现例如每一个小时检测是否有计划任务,一旦有任务,消息窗口弹出提醒!

四、注册Windows服务


1、cmd打开命令行工具:如果你系统是C盘,一般命令应该如下:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe   "你的windows服务路径"

反注册如下:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe  /u "你的windows服务路径"

当然也可以用sc命令

sc create windows服务名称 binPath= "你的windows服务路径"

删除服务

sc delete windows服务名称

这样注册就完了。

2、打开服务:

运行 下输入services.msc打开服务管理。如图:

刷新,可以查看到QuartzService.如下图:

3、 启动QuartzService,回到windows服务 应用程序所在目录

以上四部分大体实现了类似一些新闻消息推送,下一篇讲讲具体程序打包、安装等实现过程。希望大家多多推荐一下

转载于:https://www.cnblogs.com/Raymond-YYC/p/3975378.html

Windows服务调用Quartz.net 实现消息调度相关推荐

  1. windows服务调用Owin写一个http API 报错 调用的目标发生了异常。

    在使用owin开发windows服务的时候,在部署的时候报如下错误: 2016-07-02 11:39:48:  读取配置信息失败:调用的目标发生了异常.   在 System.RuntimeMeth ...

  2. Windows服务调用Office时,未将对象引用的实例

    Windows键+R键                         回车 输入:comexp.msc -32               回车 点击控制台根节点--组件服务--计算机--我的电脑- ...

  3. Quartz.NET 2.0 学习笔记(5) :实例创建Windows服务实现任务调度 Quartz.NET 项目地址 http://quartznet.sourceforge.net/ Quar

    Quartz.NET 2.0 学习笔记(5) :实例创建Windows服务实现任务调度 Quartz.NET 项目地址 http://quartznet.sourceforge.net/ Quartz ...

  4. Windows服务使用log4net记录日志

    该文章是系列文章 基于.NetCore和ABP框架如何让Windows服务执行Quartz定时作业 的其中一篇. 比较流行的日志组件有以下四种,Topshelf都有相应的组件提供 log4net NL ...

  5. C# 定时任务 调度框架 WebWork (Quartz.NET) Web版的Windows服务

    说起这个,还是觉得很自豪的(另外这里还要特别感谢Nick同学),至少目前我没有见到有这样现成框架,这个东西主要是用来调度任务的,就是根据时间定时执行一个任务,而这个任务你可以用C# 写成一个一个的dl ...

  6. windows 服务实现定时任务调度(Quartz.Net)

    我们通常在一些情况下需要软件具有一个自动执行某些任务的功能,但是又不希望直接启动软件,或者每次都要手动的来启动软件,这时我们可可以考虑到windows服务了. 首先创建一个windows服务项目(详细 ...

  7. SpringCloud微服务-服务注册发现-负载均衡-服务调用-服务降级-服务网关-配置中心-消息总线-消息驱动-链路追踪-alibaba-nacos-sentinel-seata理论原理分析

    SpringCloud理论技术 概述 ​ Spring Cloud是一系列框架的有序集合.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中心.消息总 ...

  8. Quartz+TopShelf实现Windows服务作业调度 (转载)

    Quartz:首先我贴出来了两段代码(下方),可以看出,首先会根据配置文件(quartz.config),包装出一个Quartz.Core.QuartzScheduler instance,这是一个调 ...

  9. 服务端Skynet(二)——消息调度机制

    服务端Skynet(二)--消息调度机制 文章目录 服务端Skynet(二)--消息调度机制 1.提前了解知识 1.1.互斥锁(mutex lock : **mut**ual **ex**clusio ...

最新文章

  1. 不要以为用了云,就不要运维
  2. Apache 2.2 虚拟主机配置(本人推荐的)
  3. Android NFC 开发实例
  4. 【数据分析】年轻人逃离大城市之后的下一站选哪儿?用数据来为你揭晓
  5. C++中的继承(三)
  6. vivo应用商店电脑版_VIVO应用商店代理商江湖的那些关系
  7. 二、uniapp项目(分段器的使用、scroll-view、视频下载、转发)
  8. amr文件格式分析【转http://blog.csdn.net/dinggo/article/details/1966444】
  9. qt读oracle时间戳,QT利用QDateTime获取当前时间戳的方法toTime_t
  10. phpcms调用后台上传的img图片 - 代码篇
  11. python做大型网站_django可以开发大型网站吗
  12. vue 动态scss变量,包含16进制转rgba,rgba转16进制
  13. 较完整的 bean生命周期
  14. 载波频率成分法——理论公式
  15. 移动鼠标计算鼠标偏移量
  16. 《极客与团队》一HRT实战
  17. Java日期时间主要API:java.time.Duration类和java.time.Period类
  18. mybatis的大于小于号转义符号
  19. 嵌入式系统与普适计算
  20. win10 任务栏打开直接显示【此电脑】的设置方法

热门文章

  1. 水位传感器c语言程序,基于STC89C51单片机的水位传感器控制系统设计.doc
  2. 云厂商下一块必争之地就是它了!
  3. HNOI2016D1T3 树 题解
  4. Openshift概念
  5. paypal余额限制_如何将您的PayPal余额转换成可以在任何地方消费的借记卡
  6. 领英辅助工具—领探,可突破领英的好友人脉限制
  7. Python中随机数的使用
  8. 读书发现一个勘误,提交了,这里是地址
  9. 曝各城市娶妻成本:深圳208万 程序员成为“妻奴”?
  10. linux网络编程 华清,网络编程(华清远见内部培训资料).ppt