I'm facing a deadlock, my code structure is similar to this:
private delegate void UpdateControlDelegate(string value);
public void UpdateControl(string value)
{
if (txtAddress.InvokeRequired)
{
txtAddress.Invoke(new UpdateControlDelegate(UpdateControl), value);
}
else
{
txtAddress.Text = value; // This is in GroupBox1
txtValue.Text = value; // This is in GroupBox2
}
}
class ThreadHandler
{
List<string> _list = new List<string>();
object _criticalSection = new object();
public ThreadHandler()
{
new Thread(new ThreadStart(Run)).Start();
}
public static ThreadHandler _threadHandler = null;
public static ThreadHandler GetThreadHandler()
{
if (_threadHandler == null)
{
_threadHandler = new ThreadHandler();
}
return _threadHandler;
}
public void Run()
{
while (true)
{
// some code
lock (_criticalSection)
{
foreach (string str in _list)
{
// some Code
}
}
// some code
Thread.Sleep(SomeTime);
}
}
public void AddItem(string item)
{
lock (_criticalSection)
{
_list.Add(item);
}
}
public void RemoveItem(string item)
{
lock (_criticalSection)
{
_list.Remove(item);
}
}
}
But using the same code, I just modified the UpdateControl method like this:
private delegate void UpdateControlDelegate(string value);
public void UpdateControl(string value)
{
if (InvokeRequired)
{
BeginInvoke(new UpdateControlDelegate(UpdateControl), value);
}
else
{
txtAddress.Text = value; // This is in GroupBox1
txtValue.Text = value; // This is in GroupBox2
}
}
This is working fine. What is the problem?
The problem is almost certainly that you're acquiring the lock within a background thread, then calling Control.Invoke, and invoking a delegate (on the UI thread) which tries to acquire the same lock. It can't do that, because the other thread holds the lock - and will keep holding the lock while it waits for the UI operation to complete.
Admittedly there's no locking within the UpdateControl method you've posted, but I suspect that's not the complete code - and you haven't shown where you're using AddItem or RemoveItem.
I note that GetThreadHandler() isn't thread-safe, by the way - that looks like a bug to me...
Are you calling AddItem and RemoveItem from the main thread while calling UpdateControl from the worker thread? That will cause deadlocks.
Here is my code,
public class ValueReader
{
List<IDataReader> _list = new List<IDataReader>();
object _criticalSection = new object();
public ValueReader()
{
//Nothign here
}
public void Attach(IDataReader reader)
{
lock(_criticalSection)
{
_list.Add(reader);
}
}
public void Detach(IDataReader reader)
{
lock(_criticalSection)
{
_list.Remove(reader);
}
}
public void Notify(string value)
{
lock(_criticalSection)
{
foreach(IDataReader reader in _list)
{
reader.Update(value);
}
}
}
public void Start()
{
new Thread(new ThreadStart(Run)).Start();
}
private void Run()
{
while(true)
{
//generate value
Notify(value);
Thread.Sleep(5000);
}
}
}
public interface IDataReader
{
void UpdateControls(string value);
}
public class FirstClass : IDataReader
{
....
......
ValueReader _reader = null;
public FirstClass()
{
_reader = new ValueReader();
_reader.Start();
_reader.Attach(this);
}
private void AddToSmartClient()
{
// _reader has added to SmartClient's WorkItem
}
private delegate void UpdateControlDelegate(string value);
public void UpdateControl(string value)
{
if(txtAddress.InvokeRequired)
{
txtAddress.Invoke(new UpdateControlDelegate(UpdateControl), value);
}
else
{
txtAddress.Text = value;
txtValue.Text = value;
}
}
}
public class SecondClass : IDataReader
{
....
......
ValueReader _reader = null;
public void SecondClass()
{
_reader = ReadFromSmartClient();
_reader.Attach(this);
}
private ValueReader ReadFromSmartClient()
{
reader = //Get from SmartClient's Workitem.
return reader
}
private delegate void UpdateControlDelegate(string value);
public void UpdateControl(string value)
{
if(InvokeRequired)
{
BeginInvoke(new UpdateControlDelegate(UpdateControl), value);
}
else
{
control1.Text = value;
control2.Text = value;
}
}
}
I invokes only FirstClass for some time. In this case its working fine. After some time i invoked the Second class, at this time while calling Attach from secondClass the application is hanging.(i monitered that its comming until Attach methods's lock(_criticalSection).
After some time i converter the Update control in the Frist Class as follow
public void UpdateControl(string value)
{
if(InvokeRequired)
{
BeginInvoke(new UpdateControlDelegate(UpdateControl), value);
}
else
{
txtAddress.Text = value;
txtValue.Text = value;
}
}
This is working well after invoking the SecondClass also. Why its happening?
Related
I'm not finding the bug, but this thread is stopping after some time of execution, it returns a message "Thread was being aborted."
Sometimes it takes a hour, in another takes four, I can't find a patern, in some cases it never stops, but I can't find anything relate to it
using System.Threading;
namespace NewMVC.infraestructure
{
public class Thread_iFood
{
private static bool inicializado = false;
static Thread_iFood instance = null;
static readonly object padlock = new object();
private const int timer = 30000;
static Timer thProcessaRet = new Timer(PollingIfood, null, Timeout.Infinite, Timeout.Infinite);
private Thread_iFood()
{
}
public static void Reiniciar()
{
inicializado = false;
instance = null;
}
public static Thread_iFood GetInstance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new Thread_iFood();
}
}
}
return instance;
}
}
internal static async void PollingIfood(Object obj)
{
try
{
thProcessaRet.Change(Timeout.Infinite, Timeout.Infinite);
MetodosAuxiliares.BuscaPedidosIFood();
}
catch (Exception e)
{
LogErros.GravaLog(e, "Thread_iFood/PollingIfood");
//here is where is stopping (Thread was being aborted.)
}
finally
{
thProcessaRet.Change(timer, Timeout.Infinite);
}
}
public void Inicializa()
{
if (!inicializado)
{
inicializado = true;
thProcessaRet.Change(timer, timer);
}
}
}
}
Example Code (I use Semaphore rather than lock to "lock" that bool member):
public class MsgSendHandler
{
private bool _isSocketSending = false;
private Semaphore _socketSendingSem = new Semaphore(1, 1);
public void Send(INetMsg msg)
{
// Add Msg To MsgQueue
TrySendNext();
}
private void SendCallback(IAsyncResult ar)
{
// Finish Send
_socketSendingSem.WaitOne();
_isSocketSending = false;
_socketSendingSem.Release();
TrySendNext();
}
private bool TrySendNext()
{
_socketSendingSem.WaitOne();
if (_isSocketSending)
return false;
_isSocketSending = true;
_socketSendingSem.Release();
// Socket Begin Send => SendCallback
return true;
}
}
Can I "lock" a value type like this? Is there any better solution?
Expanding on comment:
The way I created mutli-threaded functionality in Unity3D was to have a Dispatcher class that is called once per frame to run any Actions that have been added to a list.
Dispatcher.cs
A simple singleton class that holds the actions with an actual lock when looping through the actions.
public class Dispatcher
{
private static Dispatcher _instance;
public static Dispatcher Instance
{
get
{
if(_instance == null)
{
_instance = new Dispatcher();
}
return _instance;
}
}
private List<Action> _actions = new List<Action> ();
public void AddAction(Action action)
{
lock (_actions)
{
_actions.Add(action);
}
}
public void CompleteActions()
{
lock (_actions)
{
foreach (Action action in _actions)
{
action();
}
}
_actions.Clear();
}
public void ClearActions()
{
lock (_actions)
{
_actions.Clear();
}
}
}
DispatcherUpdate.cs
Another simple class that's added to a GameObject within the scene to call the Dispatcher to Complete the aquired Actions.
public class DispatcherUpdate : MonoBehaviour
{
private void Awake()
{
Dispatcher.Instance.ClearActions();
}
private void Update()
{
Dispatcher.Instance.CompleteActions();
}
}
Usage
Dispatcher.Instance.AddAction(() => TrySendNext());
This is the method I've used for Async multi-threading with SignalR
This question already has answers here:
Use Unity API from another Thread or call a function in the main Thread
(5 answers)
Closed 6 years ago.
I'm having trouble with a UnityEngine version. (Can't upgrade, game is not mine)
The server RANDOMLY crashes when a specific UnityEngine method is used in a timer/thread (It was fixed in a version, I read It)
It happens totally random, I get a crash log, that starts from the timer/thread and ends at a UnityEngine method. (This never happens when I use It in the main thread)
My question is that Is It possible somehow to call the method from the main thread if the current thread != with the main thread?
Any help is appreciated
This Loom class is able to call the specific method from the Main thread, this is how you do It:
public class Loom : MonoBehaviour
{
public static int maxThreads = 10;
static int numThreads;
private static Loom _current;
private int _count;
public static Loom Current
{
get
{
Initialize();
return _current;
}
}
public void Awake()
{
_current = this;
initialized = true;
}
static bool initialized;
static void Initialize()
{
if (!initialized)
{
if (!Application.isPlaying)
return;
initialized = true;
var g = new GameObject("Loom");
_current = g.AddComponent<Loom>();
}
}
private List<Action> _actions = new List<Action>();
public struct DelayedQueueItem
{
public float time;
public Action action;
}
private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();
List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>();
public static void QueueOnMainThread(Action action)
{
QueueOnMainThread(action, 0f);
}
public static void QueueOnMainThread(Action action, float time)
{
if (time != 0)
{
lock (Current._delayed)
{
Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = action });
}
}
else
{
lock (Current._actions)
{
Current._actions.Add(action);
}
}
}
public static Thread RunAsync(Action a)
{
Initialize();
while (numThreads >= maxThreads)
{
Thread.Sleep(1);
}
Interlocked.Increment(ref numThreads);
ThreadPool.QueueUserWorkItem(RunAction, a);
return null;
}
private static void RunAction(object action)
{
try
{
((Action)action)();
}
catch
{
}
finally
{
Interlocked.Decrement(ref numThreads);
}
}
public void OnDisable()
{
if (_current == this)
{
_current = null;
}
}
// Use this for initialization
public void Start()
{
}
List<Action> _currentActions = new List<Action>();
// Update is called once per frame
public void Update()
{
lock (_actions)
{
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
}
foreach (var a in _currentActions)
{
a();
}
lock (_delayed)
{
_currentDelayed.Clear();
_currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time));
foreach (var item in _currentDelayed)
_delayed.Remove(item);
}
foreach (var delayed in _currentDelayed)
{
delayed.action();
}
}
}
//Usage
public void Call()
{
if (Thread.CurrentThread.ManagedThreadId != TestClass.MainThread.ManagedThreadId)
{
Loom.QueueOnMainThread(() => {
Call();
});
return;
}
Console.WriteLine("Hello");
}
Desription:
I am adding some data to list every second. After every 10 seconds, the data is saved to the database and then I clear the list. If I stop the timer, I am saving the data remaining in the list and then clearing the list and then stopping the timer.
In the above code, Let's say when I stop the timer after 11 seconds, The Class1s list should have only 1 data, but I see there are 11 datas. Can you guys tell what I am doing wrong here? Maybe my use of lock is incorrect or my code is totally incorrect
public class Class1Singleton
{
private static Class1Singleton Class1Singleton;
private static List<Class1> Class1s;
private static Timer saveClass1Timer;
private static readonly object lock1 = new object();
private Class1Singleton()
{
}
public static Class1Singleton getInstance()
{
if (Class1Singleton == null) {
try
{
Class1Singleton = new Class1Singleton();
}
catch (Exception e){}
}
return Class1Singleton;
}
public void StartTimer()
{
if (saveClass1Timer == null)
{
saveClass1Timer = new Timer(10000);
//saveClass1Timer.Interval = 10000;
saveClass1Timer.Elapsed += new ElapsedEventHandler(SaveClass1);
saveClass1Timer.Enabled = true;
}
}
public void SaveClass1(object sender, ElapsedEventArgs e)
{
try {
lock (lock1)
{
new Class1Repository().InsertAllClass1(Class1s);
ClearWorkoutList();
}
}
catch (Exception ex){}
}
public void InsertClass1(List<Class1> Class1)
{
if (Class1s == null)
{
Class1s = new List<Class1>(Class1);
}
else
{
lock (lock1)
{
Class1s.AddRange(Class1);
}
}
}
public void ClearWorkoutList()
{
if (Class1s != null)
{
Class1s.Clear();
}
}
public void StopTimer()
{
if (Class1s != null && Class1s.Count > 0)
{
lock (lock1)
{
new Class1Repository().InsertAllClass1(Class1s);
ClearWorkoutList();
}
}
if (saveClass1Timer != null && saveClass1Timer.Enabled == true)
{
saveClass1Timer.Stop();
}
}
}
I've made a few changes to your code (see comments):
public class Class1Singleton
{
// This is the way Jon Skeet recommends implementing a singleton in C#
// See http://csharpindepth.com/Articles/General/Singleton.aspx
static readonly Class1Singleton instance = new Class1Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Class1Singleton() { }
// There's only one instance of Class1Singleton so there's
// no advantage in making the members static
private List<Class1> Class1s;
private Timer saveClass1Timer;
private readonly object lock1 = new object();
Class1Singleton()
{
}
public static Class1Singleton Instance
{
get { return instance; }
}
public void StartTimer()
{
// If you're using this class in a multi-thread environment,
// all methods that access the list or timer should be locked
lock (lock1)
{
if (saveClass1Timer == null)
{
saveClass1Timer = new Timer(10000);
//saveClass1Timer.Interval = 10000;
saveClass1Timer.Elapsed += new ElapsedEventHandler(SaveClass1);
saveClass1Timer.Enabled = true;
}
}
}
// SaveClass1 doesn't need to be public
private void SaveClass1(object sender, ElapsedEventArgs e)
{
lock (lock1)
{
SaveWorkoutList();
ClearWorkoutList();
}
}
private void SaveWorkoutList()
{
//new Class1Repository().InsertAllClass1(Class1s);
}
public void InsertClass1(List<Class1> Class1)
{
lock (lock1)
{
if (Class1s == null)
Class1s = new List<Class1>(Class1);
else
Class1s.AddRange(Class1);
}
}
private void ClearWorkoutList()
{
if (Class1s != null)
{
Class1s.Clear();
}
}
public void StopTimer()
{
lock (lock1)
{
if (Class1s != null && Class1s.Count > 0)
{
SaveWorkoutList();
ClearWorkoutList();
}
if (saveClass1Timer != null && saveClass1Timer.Enabled == true)
{
saveClass1Timer.Stop();
}
}
}
}
copy paste the following code in new C# console app.
class Program
{
static void Main(string[] args)
{
var enumerator = new QueuedEnumerator<long>();
var listenerWaitHandle = Listener(enumerator);
Publisher(enumerator);
listenerWaitHandle.WaitOne();
}
private static AutoResetEvent Listener(IEnumerator<long> items)
{
var #event = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem((o) =>
{
while (items.MoveNext())
{
Console.WriteLine("Received : " + items.Current);
Thread.Sleep(2 * 1000);
}
(o as AutoResetEvent).Set();
}, #event);
return #event;
}
private static void Publisher(QueuedEnumerator<long> enumerator)
{
for (int i = 0; i < 10; i++)
{
enumerator.Set(i);
Console.WriteLine("Sended : " + i);
Thread.Sleep(1 * 1000);
}
enumerator.Finish();
}
class QueuedEnumerator<T> : IEnumerator<T>
{
private Queue _internal = Queue.Synchronized(new Queue());
private T _current;
private bool _finished;
private AutoResetEvent _setted = new AutoResetEvent(false);
public void Finish()
{
_finished = true;
_setted.Set();
}
public void Set(T item)
{
if (_internal.Count > 3)
{
Console.WriteLine("I'm full, give the listener some slack !");
Thread.Sleep(3 * 1000);
Set(item);
}
else
{
_internal.Enqueue(item);
_setted.Set();
}
}
public T Current
{
get { return _current; }
}
public void Dispose()
{
}
object System.Collections.IEnumerator.Current
{
get { return _current; }
}
public bool MoveNext()
{
if (_finished && _internal.Count == 0)
return false;
else if (_internal.Count > 0)
{
_current = (T)_internal.Dequeue();
return true;
}
else
{
_setted.WaitOne();
return MoveNext();
}
}
public void Reset()
{
}
}
}
2 threads (A,B)
A thread can provide one instance at a time and calls the Set method
B thread wants to receive a sequence of instances (provided by thread A)
So literally transforming an Add(item), Add(item), .. to a IEnumerable between different threads
Other solutions also welcome of course!
Sure - this code might not be the best way to do it, but here was my initial stab at it:
Subject<Item> toAddObservable;
ListObservable<Item> buffer;
void Init()
{
// Subjects are an IObservable we can trigger by-hand, they're the
// mutable variables of Rx
toAddObservable = new Subject(Scheduler.TaskPool);
// ListObservable will hold all our items until someone asks for them
// It will yield exactly *one* item, but only when toAddObservable
// is completed.
buffer = new ListObservable<Item>(toAddObservable);
}
void Add(Item to_add)
{
lock (this) {
// Subjects themselves are thread-safe, but we still need the lock
// to protect against the reset in FetchResults
ToAddOnAnotherThread.OnNext(to_add);
}
}
IEnumerable<Item> FetchResults()
{
IEnumerable<Item> ret = null;
buffer.Subscribe(x => ret = x);
lock (this) {
toAddObservable.OnCompleted();
Init(); // Recreate everything
}
return ret;
}