Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 监视器没有';我好像没把东西锁上_C#_.net_Multithreading_Mono - Fatal编程技术网

C# 监视器没有';我好像没把东西锁上

C# 监视器没有';我好像没把东西锁上,c#,.net,multithreading,mono,C#,.net,Multithreading,Mono,我试图实现一个基本的未来的类(是的,我知道任务,但这是出于教育目的),并且遇到了监控类的奇怪行为。该类被实现,以便它进入锁入构造函数,将退出锁的操作排队到线程池。Result getter检查实例变量以查看操作是否已完成,如果未完成,则输入lock,然后返回结果。问题是,事实上,result getter并没有等待队列操作完成,而是继续进行,从而导致错误的结果。这是密码 // The class itself public class Future<T> { private

我试图实现一个基本的
未来的
类(是的,我知道
任务
,但这是出于教育目的),并且遇到了
监控
类的奇怪行为。该类被实现,以便它进入锁入构造函数,将退出锁的操作排队到线程池。Result getter检查实例变量以查看操作是否已完成,如果未完成,则输入lock,然后返回结果。问题是,事实上,result getter并没有等待队列操作完成,而是继续进行,从而导致错误的结果。这是密码

// The class itself
public class Future<T>
{
    private readonly Func<T> _f;
    private volatile bool _complete = false;
    private T _result;
    private Exception _error = new Exception("WTF");
    private volatile bool _success = false;
    private readonly ConcurrentStack<Action<T>> _callbacks = new ConcurrentStack<Action<T>>();
    private readonly ConcurrentStack<Action<Exception>> _errbacks = new ConcurrentStack<Action<Exception>>();
    private readonly object _lock = new object();

    public Future(Func<T> f)
    {
        _f = f;
        Monitor.Enter(_lock);
        ThreadPool.QueueUserWorkItem(Run);
    }

    public void OnSuccess(Action<T> a)
    {
        _callbacks.Push(a);
        if (_complete && _success)
            a(_result);
    }

    public void OnError(Action<Exception> a)
    {
        _errbacks.Push(a);
        if (_complete && !_success)
            a(_error);
    }

    private void Run(object state)
    {
        try {
            _result = _f();
            _success = true;
            _complete = true;
            foreach (var cb in _callbacks) {
                cb(_result);
            }
        } catch (Exception e) {
            _error = e;
            _complete = true;
            foreach (var cb in _errbacks) {
                cb(e);
            }
        } finally {
            Monitor.Exit(_lock);
        }
    }

    public T Result {
        get {
            if (!_complete) {
                Monitor.Enter(_lock);
            }
            if (_success) {
                return _result;
            } else {
                Console.WriteLine("Throwing error complete={0} success={1}", _complete, _success); 
                throw _error;
            }
        } 
    }

        // Failing test
        public void TestResultSuccess() {
        var f = new Future<int>(() => 1);
        var x = f.Result;
        Assert.AreEqual (1, x);
    }
//类本身
公共阶级的未来
{
私有只读函数;
私有易失性bool_complete=false;
私人T_结果;
私有异常_error=新异常(“WTF”);
私有易失性bool_success=false;
私有只读ConcurrentStack _回调=新ConcurrentStack();
私有只读ConcurrentStack _errbacks=新ConcurrentStack();
私有只读对象_lock=新对象();
公共未来(Func f)
{
_f=f;
监视器。输入(_lock);
ThreadPool.QueueUserWorkItem(运行);
}
成功时公开作废(动作a)
{
_回调。推送(a);
如果(_完成&&u成功)
a(_结果);
}
公共无效申报人(行动a)
{
_推(a);
如果(_complete&&!_success)
a(_错误);
}
私有无效运行(对象状态)
{
试一试{
_结果=_f();
_成功=真实;
_完整=正确;
foreach(var cb in_回调){
cb(_结果);
}
}捕获(例外e){
_误差=e;
_完整=正确;
foreach(变量cb in_errbacks){
cb(e);
}
}最后{
监视器。退出(_锁定);
}
}
公众对结果的怀疑{
得到{
如果(!\u完成){
监视器。输入(_lock);
}
如果(成功){
返回结果;
}否则{
WriteLine(“抛出错误完成={0}成功={1}”,\u完成,\u成功);
抛出错误;
}
} 
}
//失败测试
public void TestResultSuccess(){
var f=新未来(()=>1);
var x=f.结果;
Assert.AreEqual(1,x);
}

我在Mac OS X 10.9上使用Mono 3.2.3。

只有获得锁的线程才能退出锁。您不能
在调用线程的构造函数中输入它,然后
在完成时从线程池退出-线程池工作线程没有锁

反过来说:可能是同一个线程创建了访问getter的未来:允许再次进入:它是重新进入的。此外,您需要退出的次数与进入的次数相同,否则它实际上不会被释放


基本上,我不认为监控是正确的方法。

不同的
未来的
使用不同的锁,所以问题似乎在你这边。你似乎需要一个共享的
\u锁
。Mono是否有
任务
/
任务完成源代码
?“因为那样会简单得多…”Vlad推测是OP I他说的是“在单一未来的背景下”…@MarcGravel:不确定:毕竟,每个
Future
在其构造函数中只锁定一次。@MarcGravel我自己实现futures是为了更好地理解它们的工作原理。谢谢,我有点错过了
Monitor
文档中的这一部分。这里使用的正确同步原语是什么?@synapse,如果你愿意的话它开始工作(即关注简单),然后
ManualResetEvent
。如果您希望它高效工作,那么它可能涉及联锁标志检查等