csharp
namespace taskTest
{
using System;
using System.Threading;
using System.Threading.Tasks;
public class MyService
{
private Task? workTask;
private readonly SemaphoreSlim semaphore = new SemaphoreSlim(0, 1); // 初始为 0,Start() 启动时手动放行
private readonly CancellationTokenSource cts = new CancellationTokenSource();
private volatile bool autoReleaseSemaphore = true; // 控制 ProcessAsync 是否自动 Release
public void Start()
{
Console.WriteLine("Starting service");
autoReleaseSemaphore = true;
semaphore.Release(); // 初始启动一次
workTask = Task.Run(() => TreadJob(cts.Token));
Console.WriteLine("Service started, task ID: " + workTask.Id);
}
public void Pause()
{
Console.WriteLine("Pausing service...");
autoReleaseSemaphore = false; // 禁止 ProcessAsync 自动 Release
}
public void Resume()
{
Console.WriteLine("Resuming service...");
autoReleaseSemaphore = true; // 允许 ProcessAsync 自动 Release
semaphore.Release(); // 手动触发一次 Release,唤醒阻塞的 WaitAsync
}
public void Stop()
{
Console.WriteLine("Stopping service...");
cts.Cancel();
}
private async Task TreadJob(CancellationToken token)
{
Console.WriteLine("TreadJob started...");
try
{
if (!cts.IsCancellationRequested)
{
Console.WriteLine("Working...");
await ProcessAsync(token);
}
}
catch (OperationCanceledException e)
{
Console.WriteLine(e.Message);
Console.WriteLine("Service stopped");
}
}
private async Task ProcessAsync(CancellationToken token)
{
for (int i = 0; i < 100; i++)
{
await semaphore.WaitAsync(token); // 等待信号量
token.ThrowIfCancellationRequested();
await Task.Delay(500, token);
if (autoReleaseSemaphore)
{
semaphore.Release(); // 只有当 autoReleaseSemaphore 为 true 时才 Release
}
else
{
continue;
}
Console.WriteLine($"Process.{i}");
}
}
}
}
csharp
namespace taskTest
{
internal class Program
{
static void Main(string[] args)
{
MyService service = new();
service.Start();
// 等待一段时间,确保 ProcessAsync 有机会执行
Console.ReadLine();
//Thread.Sleep(1500);
// 暂停服务
service.Pause();
Console.WriteLine("暂停了");
Console.WriteLine("按下回车启动Resume");
Console.ReadLine();
Console.WriteLine("ReadLine执行完");
service.Resume();
Console.ReadLine();
service.Stop();
Console.ReadLine();
}
}
}
结果:

在PLC中的应用:
csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using S7.Net;
namespace taskTest
{
public class S7ConnServiceImpl : IS7ConnService
{
public S7ConnServiceImpl(Db95DeviceHis db95DeviceHis)
{
this.db95DeviceHis = db95DeviceHis;
}
private static readonly object lockObj = new object(); // 创建一个对象作为锁
private Db95DeviceHis db95DeviceHis;
private bool myIsConnected = false;
private int errorTimes = 0;
private CancellationTokenSource cts = new();
private readonly SemaphoreSlim semaphore = new SemaphoreSlim(0, 1); // 初始为 0,Start() 启动时手动放行
private volatile bool autoReleaseSemaphore = true; // 控制 ProcessAsync 是否自动 Release
public bool MyIsConnected
{
get => myIsConnected;
set => myIsConnected = value;
}
private Plc s7Plc = null;
public Plc S7Plc => s7Plc;
public void ConnPlc(string myIp, int dbNum, int startByte)
{
return;
}
public void ConnPlc(string myIp)
{
autoReleaseSemaphore = true;
semaphore.Release(); // 初始启动一次
try
{
Task.Factory.StartNew(
async () =>
{
while (!cts.IsCancellationRequested)
{
if (s7Plc == null || !MyIsConnected)
{
try
{
s7Plc = new Plc(CpuType.S71500, myIp, 0, 1);
s7Plc.Open();
s7Plc.ReadTimeout = 620;
s7Plc.WriteTimeout = 620;
//ctsRead1 = new();
//ctsRead2 = new();
MyIsConnected = s7Plc.IsConnected;
if (MyIsConnected)
{
Console.WriteLine("PlcSucessConn!");
}
}
catch (PlcException ex)
{
errorTimes++;
s7Plc.Close();
s7Plc = null;
MyIsConnected = false;
Console.WriteLine(ex.Message);
Console.WriteLine("ErrorsTime:" + errorTimes);
await Task.Delay(2000);
}
}
else if (MyIsConnected)
{
try
{
MyIsConnected = s7Plc.IsConnected;
await semaphore.WaitAsync(cts.Token); // 等待信号量
cts.Token.ThrowIfCancellationRequested();
await Task.Delay(200);
errorTimes = 0;
if (autoReleaseSemaphore)
{
semaphore.Release(); // 只有当 autoReleaseSemaphore 为 true 时才 Release
}
else
{
continue;
}
var tempDb95DeviceHis =
await S7Plc.ReadClassAsync<Db95DeviceHis>(95, 0);
lock (lockObj)
{
if (tempDb95DeviceHis != null)
{
CopyProperties(tempDb95DeviceHis, db95DeviceHis);
}
Console.WriteLine(db95DeviceHis.Kr500Trigger);
Console.WriteLine(db95DeviceHis.Kr16Time);
}
}
catch (PlcException ex)
{
errorTimes++;
await Task.Delay(2000);
Console.WriteLine($"读取时发生错误:{ex.Message}");
Console.WriteLine($"读取时发生错误次数:{errorTimes}");
s7Plc.Close();
MyIsConnected = false;
s7Plc = null;
}
}
}
},
cts.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default
);
}
catch (OperationCanceledException e)
{
Console.WriteLine(e.Message);
Console.WriteLine("Service stopped");
}
}
public void Pause()
{
Console.WriteLine("Pausing service...");
autoReleaseSemaphore = false; // 禁止 ProcessAsync 自动 Release
}
public void Resume()
{
Console.WriteLine("Resuming service...");
autoReleaseSemaphore = true; // 允许 ProcessAsync 自动 Release
semaphore.Release(); // 手动触发一次 Release,唤醒阻塞的 WaitAsync
}
public void Stop()
{
Console.WriteLine("Stopping service...");
cts.Cancel();
}
/// <summary>
/// 反射复制属性值
/// </summary>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <exception cref="ArgumentNullException"></exception>
public void CopyProperties(object source, object destination)
{
if (source == null || destination == null)
{
throw new ArgumentNullException("Either source or destination is null.");
}
Type sourceType = source.GetType();
Type targetType = destination.GetType();
foreach (
PropertyInfo sourceProperty in sourceType.GetProperties(
BindingFlags.Public | BindingFlags.Instance
)
)
{
PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name);
if (
targetProperty != null
&& targetProperty.CanWrite
&& sourceProperty.PropertyType == targetProperty.PropertyType
)
{
targetProperty.SetValue(destination, sourceProperty.GetValue(source));
}
}
}
}
}
csharp
public class Db95DeviceHis : INotifyPropertyChanged
{
public int Ret { get; set; }
public float Kr16Time { get; set; }
public float Kr500Time { get; set; }
public float Dizuo1Time { get; set; }
public float Dizuo2Time { get; set; }
public float Dizuo3Time { get; set; }
public float Kj1Time { get; set; }
public float Kj2Time { get; set; }
public float Kj3Time { get; set; }
public float ZhouTime { get; set; }
public float DamoTime { get; set; }
public bool Kr16Trigger
{
get => kr16Trigger;
set
{
if (kr16Trigger != value && value == true)
{
NotifyPropertyChanged();
}
kr16Trigger = value;
}
}
public bool Kr500Trigger
{
get => kr500Trigger;
set
{
if (kr500Trigger != value && value == true)
{
NotifyPropertyChanged();
}
kr500Trigger = value;
}
}
private bool kr16Trigger;
private bool kr500Trigger;
public virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler? PropertyChanged;
}
csharp
public interface IS7ConnService
{
void ConnPlc(string myIp, int dbNum, int startByte);
void ConnPlc(string myIp);
bool MyIsConnected
{
get;
}
Plc S7Plc { get; }
}