请教一个线程同步的问题

分号 2016-09-23 09:07:38
假设有这样一个场景:
有一个网吧,网吧里有几十台电脑,然后有很多人去上网。每下机一个人,就有下一个人进来继续上网。

我设置了一个信号量Sempahore(我使用的是System.Threading.Semaphore),用于控制同时能进入网吧的总人数,相当于在网吧门口安排了一个大爷,他拦住大家,只允许一定人数进入网吧。

然后我的问题有2个:
1,进入网吧的人,还要自己去找哪台电脑空了。我记得好像在哪里看过类似的一篇文章,说是通过设置Sempahore,就可以直接做到把被保护的资源(所有的网吧电脑)中的一个空闲资源(空出来的电脑)交给等待者(等待上网的人),也就是说当调用Sempahore的Release方法时,第一个结束等待的线程(等待上网的人)直接就拿到空闲的资源(空出来的电脑),但我忘记具体怎么实现了。
2,有没有办法通知在外面等待的人都散了,不要再等了?(在设置无限等待的前提下)
...全文
265 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
分号 2016-10-27
  • 打赏
  • 举报
回复
引用 8 楼 Forty2 的回复:
[quote=引用 7 楼 novaliang 的回复:] Forty2,very good! 可惜的是第一个问题没找到答案,算了,结贴吧,我自己去找之前看过的文章。
如果有一个人在int i = WaitHandle.WaitAny...这里阻塞等待, 那么,容量信号.Release();就会让出一个空位,等待的第一个人就会自动获得位置。 我想,这对应你的第一个问题。[/quote] 啊,你来的太迟啦~~~不过还是谢谢你啦
分号 2016-09-26
  • 打赏
  • 举报
回复
Forty2,very good! 可惜的是第一个问题没找到答案,算了,结贴吧,我自己去找之前看过的文章。
Forty2 2016-09-26
  • 打赏
  • 举报
回复
引用 7 楼 novaliang 的回复:
Forty2,very good! 可惜的是第一个问题没找到答案,算了,结贴吧,我自己去找之前看过的文章。
如果有一个人在int i = WaitHandle.WaitAny...这里阻塞等待, 那么,容量信号.Release();就会让出一个空位,等待的第一个人就会自动获得位置。 我想,这对应你的第一个问题。
Forty2 2016-09-24
  • 打赏
  • 举报
回复
方法可以有好多种。要支持赶人,比较常规就是使用另外一个信号量。

class 网吧
{
    Semaphore 容量信号;
    ManualResetEvent 关门信号;
    WaitHandle[] 多种信号;

    public 网吧(int 最大容量 = 5)
    {
        容量信号 = new Semaphore(0, 最大容量);
        关门信号 = new ManualResetEvent(false);
        多种信号 = new WaitHandle[] { 容量信号, 关门信号 };
    }

    public void 上网(bool 死等 = false)
    {
        int i = WaitHandle.WaitAny(多种信号, 死等 ? Timeout.Infinite : 0);
        if (i == 1)
        {
            Console.WriteLine("网吧关门赶人了");
            return;
        }
        else if (i == WaitHandle.WaitTimeout)
        {
            Console.WriteLine("网吧当场没有空位");
            return;
        }
        try
        {
            Console.WriteLine("上网");
            Thread.Sleep(10 * 1000);
        }
        finally
        {
            Console.WriteLine("下网,让出位置");
            容量信号.Release();
        }
    }

    public void 关门()
    {
        关门信号.Set();
    }
}
分号 2016-09-24
  • 打赏
  • 举报
回复
对于第2个问题,昨晚测试了一下,摸索出了一点收获,说出来请大家帮忙看看对不对。 对于外面的上网狂热分子,门口的大爷说什么他们都不肯散去(Semaphore.Close(),Semaphore.Dispose()),最后网吧只好允许一个人进来看看,那个人进来看了之后发现确实没有空机,而且那些正在上网的人都选择了玩到十一结束,时间太长了,于是他出去对外面的人说,走吧,都散了,玩不了了,但任然有不相信的人进来看看,后面的结果都一样,最后大家都散了。 网吧吸取这次经验,告诉门口大爷,可以多进一个人。

static Semaphore _semaphore = null;
static bool bSanle = false;
public void init()
{
...
_semaphore = new Semaphore(computerCount, computerCount + 1);
...
}

public void DouSanLeBa()
{
...
bSanle = true;
_sempahore.Release();
...
}

public void ShangWang()
{
_semaphore.WaitOne();
if (bSanle)
{
return;
}
...
}
闭包客 2016-09-23
  • 打赏
  • 举报
回复
1、编写这个大爷。 2、好像没这个必要?
  • 打赏
  • 举报
回复
设置下IsBackground
分号 2016-09-23
  • 打赏
  • 举报
回复
呃,第二个问题,可能你们没碰到这样的需求,或者你们有更高明的解决办法从而不会像我这样做。 是这样的,如果所有在外面等待的人今天必须要上网,不上就不走了,相当于我开启了一个无限等待。但是网吧下班了(也许有的网吧会下班吧),外面的人就不得不走了。 业务逻辑就是,我开启一个任务要执行,但考虑到客户会没有耐性等待全部执行完成,而直接关闭程序,那我必须要能优雅的关闭程序。 我想到的一个方法就是如下的伪代码:

static bool bQuit = false;
public void Close()
{
Sempahore.Release(nCount);
bQuit = true;
}

public void DoWork()
{
Sempahore.WaitOne();
if (bQuit)
{
return;
}
...
}
dlijian 2016-09-23
  • 打赏
  • 举报
回复
1.线程池 控制最大数并发线程 2.真没必要,如果一定要做的话,个人觉得加个计时器,线程池并发线程已经是最大,然后配合计时器,来进行后续操作

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧