Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/309.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#_Multithreading - Fatal编程技术网

C#无锁定生产者或消费者的线程

C#无锁定生产者或消费者的线程,c#,multithreading,C#,Multithreading,TLDR;主要问题的版本: 在使用线程时,如果不删除列表内容(重新组织顺序),并且仅在完全添加新对象后读取新对象,那么在使用一个线程读取列表内容,而使用另一个线程写入列表内容是否安全 当一个线程将一个Int从“旧值”更新为“新值”时,如果另一个线程读取该Int,返回的值既不是“旧值”也不是“新值”,是否存在风险 如果某个关键区域很忙,线程是否可以“跳过”该区域,而不只是进入睡眠状态并等待区域释放 我有两段代码在不同的线程中运行,我想让其中一段充当另一段的生产者。我不希望任何一个线程在等待访问时“

TLDR;主要问题的版本:

  • 在使用线程时,如果不删除列表内容(重新组织顺序),并且仅在完全添加新对象后读取新对象,那么在使用一个线程读取列表内容,而使用另一个线程写入列表内容是否安全

  • 当一个线程将一个Int从“旧值”更新为“新值”时,如果另一个线程读取该Int,返回的值既不是“旧值”也不是“新值”,是否存在风险

  • 如果某个关键区域很忙,线程是否可以“跳过”该区域,而不只是进入睡眠状态并等待区域释放

  • 我有两段代码在不同的线程中运行,我想让其中一段充当另一段的生产者。我不希望任何一个线程在等待访问时“休眠”,而是在另一个线程正在访问时,在其内部代码中向前跳

    我最初的计划是通过这种方法共享数据(一旦计数器足够高,就切换到第二个列表以避免溢出)


    流的伪代码,正如我最初打算的那样

    Producer
    {
    Int counterProducer;
    bufferedObject newlyProducedObject;
    List <buffered_Object> objectsProducer;
        while(true) 
        {
            <Do stuff until a new product is created and added to newlyProducedObject>;
            objectsProducer.add(newlyProducedObject_Object);
            counterProducer++
        }
    }
    
    
    Consumer
    {
    Int counterConsumer;
    Producer objectProducer; (contains reference to Producer class)
    List <buffered_Object> personalQueue
        while(true)
            <Do useful work, such as working on personal queue, and polish nails if no personal queue>
            //get all outstanding requests and move to personal queue
            while (counterConsumer < objectProducer.GetcounterProducer())
            {
                personalQueue.add(objectProducer.GetItem(counterconsumer+1));
                counterConsumer++;
            }
    }
    
    制作人
    {
    反生产者;
    bufferedObject新建ProducedObject;
    列出目标生产者;
    while(true)
    {
    ;
    objectsProducer.add(newlyProducedObject\u对象);
    反生产者++
    }
    }
    消费者
    {
    Int反消费者;
    生产者对象生产者;(包含对生产者类的引用)
    列出个人队列
    while(true)
    //获取所有未完成的请求并移动到个人队列
    while(反消费者

    看这个,乍一看一切都很好,我知道我不会从队列中检索半构造的产品,因此列表的状态无论它在哪里都不会是问题,即使在生产者添加新对象时线程切换occour也是如此。这个假设是正确的,还是会有问题?(我的猜测是,当消费者要求列表中的特定位置时,新对象被添加到末尾,并且对象从未被删除,这不会成为问题)

    但引起我注意的是,当“反生产者++”处于未知值时,会出现类似的问题吗?这是否会导致临时值为“null”或某个未知值?这会是一个潜在的问题吗

    我的目标是让两个线程在等待互斥锁时都不锁定,而是继续它们的循环,这就是为什么我首先进行上述操作,因为没有锁定

    如果列表的使用会导致问题,我的解决方法是创建一个链表实现,并在两个类之间共享它,仍然使用计数器查看是否添加了新工作,并在personalQueue将新内容移动到personalQueue时保留最后位置。因此,生产者添加新链接,消费者阅读它们,并删除以前的链接。(列表上没有计数器,只有外部计数器可以知道添加和删除了多少)


    避免counterConsumer++风险的替代伪代码(需要帮助)

    制作人
    {
    国际公共反生产者;
    国际私人反生产者;
    bufferedObject新建ProducedObject;
    列出目标生产者;
    while(true)
    {
    ;
    objectsProducer.add(newlyProducedObject\u对象);
    私人反生产者++
    }
    }
    消费者
    {
    Int反消费者;
    生产者对象生产者;(包含对生产者类的引用)
    列出个人队列
    while(true)
    //获取所有未完成的请求并移动到个人队列
    while(反消费者

    因此,代码第二部分的目标,我还没有弄清楚如何编写代码,是使两个类都不等待另一个类,以防另一个类处于更新publicCounterProducer的“关键区域”。如果我正确读取了锁功能,线程将进入睡眠状态,等待释放,这不是我想要的。但最终可能不得不使用它,在这种情况下,第一个伪代码就可以做到这一点,并在获取值时设置一个“锁”

    希望你能帮我解决很多问题

    在使用线程时,如果不删除列表内容(重新组织顺序),并且仅在完全添加新对象后读取新对象,那么在使用一个线程读取列表内容,而使用另一个线程写入列表内容是否安全

    不,它不是。向列表中添加项的副作用可能是重新分配其基础数组。
    List
    的当前实现在将旧数据复制到内部引用之前更新内部引用,因此多个线程可能会观察到大小正确但不包含数据的列表

    当一个线程将一个Int从“旧值”更新为“新值”时,如果另一个线程读取该Int,返回的值既不是“旧值”也不是“新值”,是否存在风险

    不,int更新是原子的。但是,如果两个线程同时递增
    counterProducer
    ,则会出错。您应该使用来增加它

    如果某个关键区域很忙,线程是否可以“跳过”该区域,而不只是进入睡眠状态并等待区域释放

    否,但您可以使用(例如)查看等待是否成功,并相应地进行分支
    WaitHandle
    由几个同步类实现,例如
    ManualResetEvent

    顺便问一下,您是否有理由不使用内置的生产者/消费者类,例如?BlockingCollection易于使用(阅读后
    Producer
    {
    Int publicCounterProducer;
    Int privateCounterProducer;
    bufferedObject newlyProducedObject;
    List <buffered_Object> objectsProducer;
        while(true) 
        {
            <Do stuff until a new product is created and added to newlyProducedObject>;
            objectsProducer.add(newlyProducedObject_Object);
            privateCounterProducer++
            <Need Help: Some code that updates the publicCounterProducer to the privateCounterProducer if that variable is not 
    
    locked, else skips ahead, and the counter will get updated at next pass, at some point the consumer must be done reading stuff, and 
    
    new stuff is prepared already>      
        }
    }
    
    
    Consumer
    {
    Int counterConsumer;
    Producer objectProducer; (contains reference to Producer class)
    List <buffered_Object> personalQueue
        while(true)
            <Do useful work, such as working on personal queue, and polish nails if no personal queue>
            //get all outstanding requests and move to personal queue
            <Need Help: tries to read the publicProducerCounter and set readProducerCounter to this, else skips this code>
            while (counterConsumer < readProducerCounter)
            {
                personalQueue.add(objectProducer.GetItem(counterconsumer+1));
                counterConsumer++;
            }
    }