Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

线程池 threadpool<T>::run() 函数中,为什么要判断 request 非NULL? #276

Open
arglone opened this issue May 10, 2024 · 3 comments

Comments

@arglone
Copy link

arglone commented May 10, 2024

我想不到任何一种情况会导致 requestNULL,也就是下面的代码我觉得是没必要的:

    if (!request)
        continue;

threadpool<T>::run() 用的 request 最先是 WebServer::dealwithwrite()WebServer::dealwithread()append 操作进来的。append 是类似 m_pool->append(users + sockfd, 1); 这样直接操作的 users 数组。但是我们看到 WebServer::WebServer() 构造函数内是直接 users = new http_conn[MAX_FD]; 的,因此 users + sockfd 在任何时候都不可能为NULL。即使 WebServer::~WebServer() 析构函数内做了 delete[] users;,但 delete 关键字本身也不会改变指针的值,所以根本想不到为什么代码中要判断 requestNULL....

看看有无大佬分析一下这里。

@arglone
Copy link
Author

arglone commented May 11, 2024

我又发现threadpool<T>::run()还有一部分也有问题,明明已经wait到了semaphore,还要再判断一次队列非空:

        m_queuestat.wait();
        m_queuelocker.lock();
        if (m_workqueue.empty())
        {
            m_queuelocker.unlock();
            continue;
        }

我也想不到任何触发这个if的情况。我查了下,sem_post() 是只会唤醒一个线程的。而且,如果想要 lock(),必须要先 wait(),所以也不存在 wait() 醒来后 lock() 没抢过的情况。总之,就是怎么也不会存在虚假唤醒的情况。

我只能理解这里是在做防御性编程了。。
但是把,如果是防御性编程,connection_pool::GetConnection() 中也是有几乎一样的代码,不过,此时却又没有这样再次判断了。真的让人迷惑。

@handsome-rgb
Copy link

同问

@diandengpao
Copy link

第一个应该仅仅是防御性编程, 因为调用 process 前 必先 经过 read_once, 所以确实不会有null的风险。
第二个我可以解释。
sem 是 唤醒线程的,而m_queuelocker 是 m_workqueue的对应锁,所以唤醒线程后如果要操作 m_workqueue 依旧必须要上锁。
至于为什么需要判m_workqueue为空,则是虚假唤醒的问题。
由于作者风格较古老,所以代码冗长。
详情可见新的c++ 生产者消费者模型。这里贴下个人写的,仅供参考

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>

using namespace std;

queue<int> gifts;
mutex mtx;
condition_variable cv;

void produce() {

	for (int i = 1; i <= 5; i++) {
		mtx.lock();
		gifts.push(i);
		mtx.unlock();

		cv.notify_one();
	}

	//约定0 为 退出
	mtx.lock();
	gifts.push(0);
	mtx.unlock();

	cv.notify_one();
}

void consume() {

	while (true) {

		unique_lock<mutex> lk(mtx);

		//一直等到 !gifts.empty() 为真
		cv.wait(lk, [] {return !gifts.empty(); });
		
		auto gift = gifts.front();
		gifts.pop();

		lk.unlock();

		cout << "礼物:" << gift << endl;

		if (gift == 0)
			break;
	}
}

int main() {
	

	thread(produce).detach();

	consume();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants