C++使用队列实现多线程请求的代理检查器阻塞问题咨询
问题根因
你当前的问题核心是锁的粒度过大,同时存在共享队列访问的竞态问题:
- 你把
cpr::Get这个耗时的网络IO操作完全包裹在锁范围内,同一时间只有一个线程能执行请求,多线程完全没有起到并发作用,所有线程自然会串行等待前一个请求完成。 - 你在
while (!q.empty())处直接无锁访问共享队列,多个线程同时读取队列状态、操作队列元素会出现严重的竞态问题,这也是你直接移除锁后依然无法正常运行的原因。
解决方法
不需要移除锁,只要缩小锁的范围,仅在操作共享队列的时候持有锁,拿到代理地址后立刻释放锁,再执行网络请求即可,修正后的代码如下:
#include <stdio.h> #include <pthread.h> #include <iostream> #include <queue> #include <mutex> #include <cpr/cpr.h> #include <fmt/format.h> #define NUMT 10 using namespace std; using namespace fmt; std::mutex mut; std::queue<std::string> q; void* Checker(void* arg) { while (true) { std::string proxy; // 锁仅保护队列操作 mut.lock(); if (q.empty()) { mut.unlock(); break; } // 取出代理存到局部变量,立刻释放锁 proxy = q.front(); q.pop(); mut.unlock(); // 网络请求放在锁外执行,多个线程可以并发请求 string protocol = "socks4"; string proxyformatted = format("{0}://{1}", protocol, proxy); // 替换为你自己的webhook地址 auto r = cpr::Get(cpr::Url{ "<webhook url>" }, cpr::Proxies{ {"http", proxyformatted}, {"https", proxyformatted} }); // 可以在这里加代理有效性判断、结果输出逻辑 } return NULL; } int main(int argc, char** argv) { q.push("138.201.134.206:5678"); q.push("185.113.7.87:5678"); q.push("5.9.16.126:5678"); q.push("88.146.196.181:4153"); pthread_t tid[NUMT]; int i; int thread_args[NUMT]; for (i = 0; i < NUMT; i++) { thread_args[i] = i; pthread_create(&tid[i], NULL, Checker, (void*) &thread_args[i]); } for (i = 0; i < NUMT; i++) { pthread_join(tid[i], NULL); fprintf(stderr, "Thread %d terminated\n", i); } return 0; }
额外优化建议
- 可以使用
std::lock_guard/std::unique_lock等RAII锁包装器,避免手动管理锁出现遗漏释放的问题 - 现代C++项目更推荐使用
std::thread代替POSIX pthread接口,跨平台性更好 - 如果需要运行过程中动态添加代理到队列,可以搭配条件变量
std::condition_variable实现线程等待唤醒逻辑,避免线程空转消耗CPU
内容的提问来源于stack exchange,提问作者GoekhanDev
相关产品推荐
相关产品推荐

