1

我正在使用中间处理线程解决生产者消费者问题。当我运行 200 个这样的应用程序时,它会在大量连接超时时将系统锁定在 win7 中。不幸的是,不是以我知道如何调试它的方式。系统变得无响应,我必须使用电源按钮重新启动它。它在我的 mac 上运行良好,奇怪的是,它在安全模式下的 windows 下运行良好。

我正在使用 boost 1.44,因为这是主机应用程序使用的。

这是我的队列。我的意图是队列的大小是同步的。我已经操纵它来timed_wait确保我不会丢失通知,尽管我没有看到效果上有什么不同。

class ConcurrentQueue {
public:
    void push(const std::string& str, size_t notify_size, size_t max_size);
    std::string pop();

private:
    std::queue<std::string> queue;
    boost::mutex mutex;
    boost::condition_variable cond;
};

void ConcurrentQueue::push(
  const std::string& str, size_t notify_size, size_t max_size) {
    size_t queue_size;
    {{
        boost::mutex::scoped_lock lock(mutex);
        if (queue.size() < max_size) {
            queue.push(str);
        }
        queue_size = queue.size();
    }}
    if (queue_size >= notify_size)
        cond.notify_one();
}

std::string ConcurrentQueue::pop() {
    boost::mutex::scoped_lock lock(mutex);
    while (!queue.size())
        cond.wait(lock);
    std::string str = queue.front();
    queue.pop();
    return str;
}

这些线程使用以下队列使用 libcurl 进行处理和发送。

boost::shared_ptr<ConcurrentQueue> queue_a(new ConcurrentQueue);
boost::shared_ptr<ConcurrentQueue> queue_b(new ConcurrentQueue);

void prod_run(size_t iterations) {
    try {
        // stagger startup
        boost::this_thread::sleep(
              boost::posix_time::seconds(random_num(0, 25)));
        size_t save_frequency = random_num(41, 97);
        for (size_t i = 0; i < iterations; i++) {
            // compute
            size_t v = 1;
            for (size_t j = 2; j < (i % 7890) + 4567; j++) {
                v *= j;
                v = std::max(v % 39484, v % 85783);
            }
            // save
            if (i % save_frequency == 0) {
                std::string iv = 
                              boost::str( boost::format("%1%=%2%") % i % v );
                queue_a->push(iv, 1, 200);
            }
            sleep_frame();
        }
    } catch (boost::thread_interrupted&) {
    }
}

void prodcons_run() {
    try {
        for (;;) {
            std::string iv = queue_a->pop();
            queue_b->push(iv, 1, 200);
        }
    } catch (boost::thread_interrupted&) {
    }
}

void cons_run() {
    try {
        for (;;) {
            std::string iv = queue_b->pop();
            send_http_post("http://127.0.0.1", iv);
        }
    } catch (boost::thread_interrupted&) {
    }
}

我对以这种方式使用互斥锁的理解不应使系统无响应。如果有的话,我的应用程序会死锁并永远休眠。

有没有什么方法可以同时拥有 200 个这样的场景,而情况并非如此?

更新:

当我重新启动计算机时,大多数时候我需要重新插入 USB 键盘才能使其响应。鉴于司机的评论,我认为这可能是相关的。我尝试更新北桥驱动程序,尽管它们是最新的。我会看看是否还有其他需要注意的驱动程序。

更新:

我观察了内存、非分页池、cpu、句柄、端口,在系统响应时,它们都没有处于惊人的速度。最后可能会有一些尖峰,尽管这对我来说是不可见的。

更新:

当系统挂起时,它会停止渲染并且不响应键盘。它渲染的最后一帧仍然存在。系统听起来它仍在运行,当系统恢复运行时,事件查看器中没有任何内容表明它崩溃了。也没有故障转储文件。我将此解释为操作系统被阻止执行。

4

1 回答 1

1

互斥锁锁定使用相同锁的其他应用程序。操作系统使用的任何互斥锁都不应该(直接)对任何应用程序可用。

当然,如果互斥锁是使用操作系统以某种方式实现的,它很可能会调用操作系统,从而使用 CPU 资源。但是,互斥锁不会导致比应用程序以任何其他方式使用 CPU 资源更糟糕的行为。

当然,如果你以不恰当的方式使用锁,应用程序的不同部分可能会陷入死锁,因为函数 1 获取锁 A,然后函数 2 获取锁 B。如果函数 1 尝试获取锁 B,并且函数2 试图在释放各自的锁之前获取锁A,你就有了死锁。这里的技巧是始终以相同的顺序获取多个锁。所以如果你同时需要两个锁,总是先获取锁A,再获取锁B。

死锁不应该像这样影响操作系统——如果有的话,它会使它变得更好,但如果应用程序在死锁的情况下以某种方式“行为不端”,它可能会通过大量调用操作系统而导致问题——例如,如果锁定是由:

while (!trylock(lock))
{
      /// do nothing here
}

它可能会导致系统使用高峰。

于 2013-02-18T18:37:30.240 回答