-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathDCG_example2.cs
More file actions
218 lines (196 loc) · 6.08 KB
/
DCG_example2.cs
File metadata and controls
218 lines (196 loc) · 6.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#region Copyright
//
// Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved.
// Licensed under the MIT. See LICENSE file in the project root for full license information.
//
#endregion
using System;
using System.Iec61131Lib;
using System.Collections.Generic;
using Eclr;
using System.Threading;
using Eclr.Pcos;
using Iec61131.Engineering.Prototypes.Common;
using Iec61131.Engineering.Prototypes.Methods;
using Iec61131.Engineering.Prototypes.Types;
using Iec61131.Engineering.Prototypes.Variables;
// This pattern represents the use case that code of a FB should be executed in a background task.
// The background task executes all FBs that exist in a container.
// In this pattern an instance of an implementation class is added to the container and will not be removed till the finalization of the FB instance.
// It is important that the FB is not added directly to the container.
namespace DcgBestPracticePattern3
{
[FunctionBlock]
public class BackgroundDemoFb1
{
[Input, DataType("BOOL")]
public bool In;
[Output, DataType("DINT")]
public int Value;
// Do not permanently put a Function Block into a Container.
// This will cause a Memory leak and may cause resource leaks.
// Better lazily (when used by an active domain) create an impl class that is added to the container and will execute all logic.
private BackgroundFbImpl impl;
public BackgroundDemoFb1()
{
// Create a worker thread during construction
// Worker thread is designed to create just one thread per AppDomain although called more than once.
WorkerThread.CreateThread();
}
~BackgroundDemoFb1()
{
if (Eclr.Environment.IsPrimaryDomain(this))
{
// The finalizer is typically executed in primary domain. This is done to access object references from this
// domain in order to do clean ups.
if (impl != null)
{
Container.GetInstance().Remove(impl);
}
}
else
{
// When the type has been changed by adding, removing or changing fields by Download Changes
// then the Finalizer is executed in the secondary domain.
// In this case it is not possible to access object references from the primary domain.
}
}
[Initialization]
public void __Init()
{
}
[Execution]
public void __Process()
{
// Lazy initialization of container
if (impl == null)
{
impl = new BackgroundFbImpl();
Container.GetInstance().Add(impl);
}
impl.Process(this);
}
}
public class BackgroundFbImpl
{
private int tempResult;
public BackgroundFbImpl()
{
}
~BackgroundFbImpl()
{
}
public void Process(BackgroundDemoFb1 fb)
{
// Accessing public data of the FB
if (fb.In)
{
fb.Value = tempResult;
}
}
public void Add1()
{
tempResult++;
}
public void Add10()
{
tempResult += 10;
}
}
public class Container
{
// Implementation of singleton pattern
private static Container instance;
internal static Container GetInstance()
{
if (instance == null)
{
instance = new Container();
}
return instance;
}
private List<BackgroundFbImpl> fbs;
private Container()
{
fbs = new List<BackgroundFbImpl>();
}
~Container()
{
if (fbs != null)
{
}
}
internal void Add(BackgroundFbImpl o)
{
lock (this)
{
fbs.Add(o);
}
}
internal bool Remove(BackgroundFbImpl o)
{
lock (this)
{
fbs.Remove(o);
}
return true;
}
internal BackgroundFbImpl[] GetAll()
{
lock (this)
{
BackgroundFbImpl[] allFbs = allFbs = new BackgroundFbImpl[fbs.Count];
fbs.CopyTo(allFbs);
return allFbs;
}
}
}
#region Worker Thread
/// <summary>
/// Class creating a thread (that must be static)
/// </summary>
static class WorkerThread
{
private static Thread worker;
internal static bool CreateThread()
{
if (worker == null)
{
ThreadStart start = new ThreadStart(TaskBody);
worker = new Thread(start)
{
Priority = ThreadPriority.Lowest
};
worker.Start();
return true;
}
return false;
}
static void TaskBody()
{
while (true)
{
// Just execute jobs if the PLC state is Running
if (Resource.Running)
{
Exec();
}
Thread.Sleep(1);
}
}
private static void Exec()
{
// This example of Exec() is a very simple implementation. It gets all registered instances from the container and executes a method of it.
// Following can be optimized:
// - The array produces garbage in each cycle.
// - If the container may potentially contain a large list of FBs then process just one or some instead of all instances per cycle.
// This is more cooperative and allows lower prior tasks to get CPU time.
BackgroundFbImpl[] fbs = Container.GetInstance().GetAll();
foreach (BackgroundFbImpl fb in fbs)
{
fb.Add1();
}
}
}
#endregion
}