首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >信号量WaitOne后调用互锁

信号量WaitOne后调用互锁
EN

Stack Overflow用户
提问于 2021-09-07 08:58:23
回答 2查看 83关注 0票数 0

在并发调用GenerateLabel超过4次时,遇到以下代码阻塞信号量。在WaitOne之后,成员mCurrentScanner被用来访问扫描仪。问题是在WaitOne之后是否需要互锁函数?当WaitHandle发布时线程重新开始时,我会拒绝,但不是100%确定。

代码语言:javascript
复制
  mConcurrentLabels = new Semaphore(4, 4);

  public string GenerateLabel()
  {
    mConcurrentLabels.WaitOne();

    int current = 0;

    Interlocked.Exchange(ref current, mCurrentScanner);

    (scanner, dir) = ScanMappings[current];

    Interlocked.Increment(ref mCurrentScanner);
    mCurrentScanner %= 4;
    DoLongRunningTask();
    mConcurrentLabels.Release();
  }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-07 09:28:15

正如您所说的,信号量用于限制并发线程。但身体仍同时执行。所以锁/联锁是必需的。

更大的问题是:使用Interlocked.Exchange(ref current, mCurrentScanner);安全读取值,使用Interlocked.Increment(ref mCurrentScanner);

可以并发读取相同的值Exchange()并将其增加两次。因此,您将选择一个值两次,并跳过下一个值。

我还建议在使用信号量时使用try/finallies。

代码语言:javascript
复制
mConcurrentLabels = new Semaphore(4, 4);

public string GenerateLabel()
{
    mConcurrentLabels.WaitOne();
    try
    {
        int current = Interlocked.Increment(ref mCurrentScanner);
        
        (scanner, dir) = ScanMappings[current];
        
        // mCurrentScanner %= 4;   <------ ?
        DoLongRunningTask();
    }
    finally
    {
        mConcurrentLabels.Release();
    }
}

但是如果你需要修改mCurrentScanner,我不会使用互锁的。

代码语言:javascript
复制
mConcurrentLabels = new Semaphore(4, 4);
object mSyncRoot = new object();

public string GenerateLabel()
{
    mConcurrentLabels.WaitOne();
    try
    {
        int current;
        
        lock(mSyncRoot)
        {
            current = mCurrentScanner++;
            mCurrentScanner %= 4;
        }
        
        (scanner, dir) = ScanMappings[current];
        
        // mCurrentScanner %= 4;   <------ ?
        DoLongRunningTask();
    }
    finally
    {
        mConcurrentLabels.Release();
    }
}
票数 2
EN

Stack Overflow用户

发布于 2021-09-07 09:32:52

信号量的目的似乎是保护长期运行的任务,而不是保护对私有变量的访问。从资源管理的角度来看,这是非常有用的。例如,为了防止过多并发长时间运行的任务破坏共享资源(如数据库)。

需要使用互锁语句来保护私有变量,因为信号量允许此代码在不同线程上并发运行四次。

很好的做法是将此代码的主要部分放在try {} finally{}块中,以确保每次调用mConcurrentLabels.WaitOne()时都准确地调用mConcurrentLabels.Release()一次。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69085229

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档