简单使用线程池

本文介绍了一个使用C++实现的多线程网络下载程序,该程序能够利用线程池技术同时下载多个文件,并实时显示每个线程的下载进度。通过具体代码示例展示了如何配置线程池、设置下载任务及进度监控。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.最好会使用一种跨平台线程池库(C/C++),网站组可使用系统自带的库,来开发一个命令行网络程序,下载文件
iston-video-converter.exe

2.至少可以显示已下载的字节数。
3.设置线程池最大线程数为5。
4.使用线程池开启10个下载任务,正在现在的线程需打印(进度(即字节数),线程ID)

5.验证等待中的线程继续时是否是从线程池获取已创建好的线程,即对比线程ID.

makefile

#
#  There exist several targets which are by default empty and which can be 
#  used for execution of your targets. These targets are usually executed 
#  before and after some main targets. They are: 
#
#     .build-pre:              called before 'build' target
#     .build-post:             called after 'build' target
#     .clean-pre:              called before 'clean' target
#     .clean-post:             called after 'clean' target
#     .clobber-pre:            called before 'clobber' target
#     .clobber-post:           called after 'clobber' target
#     .all-pre:                called before 'all' target
#     .all-post:               called after 'all' target
#     .help-pre:               called before 'help' target
#     .help-post:              called after 'help' target
#
#  Targets beginning with '.' are not intended to be called on their own.
#
#  Main targets can be executed directly, and they are:
#  
#     build                    build a specific configuration
#     clean                    remove built files from a configuration
#     clobber                  remove all built files
#     all                      build all configurations
#     help                     print help mesage
#  
#  Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
#  .help-impl are implemented in nbproject/makefile-impl.mk.
#
#  Available make variables:
#
#     CND_BASEDIR                base directory for relative paths
#     CND_DISTDIR                default top distribution directory (build artifacts)
#     CND_BUILDDIR               default top build directory (object files, ...)
#     CONF                       name of current configuration
#     CND_PLATFORM_${CONF}       platform name (current configuration)
#     CND_ARTIFACT_DIR_${CONF}   directory of build artifact (current configuration)
#     CND_ARTIFACT_NAME_${CONF}  name of build artifact (current configuration)
#     CND_ARTIFACT_PATH_${CONF}  path to build artifact (current configuration)
#     CND_PACKAGE_DIR_${CONF}    directory of package (current configuration)
#     CND_PACKAGE_NAME_${CONF}   name of package (current configuration)
#     CND_PACKAGE_PATH_${CONF}   path to package (current configuration)
#
# NOCDDL


# Environment 
MKDIR=mkdir -p
CP=cp -u
CCADMIN=CCadmin
ANT=ant
MAIN_VERSION=1.0.x
LIB_VERSION=1.0.0

# build
build: .build-init .build-post

.build-pre:
# Add your pre 'build' code here...
.build-init:
	${MKDIR} dist

.build-post: .build-app-dir .build-app-resources .build-app-dll .build-impl
# Add your post 'build' code here...
	${CP} E:/software/MinGW/bin/libgcc_s_dw2-1.dll dist/${CONF}/MinGW-Windows/
#	${CP} ../../dist/${CONF}/MinGW-Windows/*.dll dist/${CONF}/MinGW-Windows/
	${CP} E:/software/project/tool/1.0.x/win32/share/Release/QX_Tool.1.0.0.dll dist/${CONF}/MinGW-Windows/
	${CP} resources/*.txt  dist/${CONF}/MinGW-Windows/
#	${CP} E:/software/Lib/communications/curl-7.28.1/win32/release/share/libcurl-4.dll dist/${CONF}/MinGW-Windows/
	${CP} E:/software/Lib/common/boost-1.46.1/win32/release/share/mt/libboost_regex-mgw44-mt-1_46_1.dll dist/${CONF}/MinGW-Windows/
	${CP} E:/software/Lib/common/boost-1.46.1/win32/release/share/mt/libboost_thread-mgw44-mt-1_46_1.dll dist/${CONF}/MinGW-Windows/
	${CP} E:/software/project/tool/win32/share/Release/QX_Tool.dll dist/${CONF}/MinGW-Windows/
#	${CP} E:/software/Lib/i18n/iconv-1.14/win32/release/share/libiconv-2.dll dist/${CONF}/MinGW-Windows/
	${CP} E:/software/Lib/communications/curl-7.28.1/win32/release/share/libcurl-4.dll dist/${CONF}/MinGW-Windows/
	
	

.build-app-dir:

.build-app-resources:

.build-app-dll:

# clean
clean: .clean-post

.clean-pre:
# Add your pre 'clean' code here...

.clean-post: .clean-impl
# Add your post 'clean' code here...


# clobber
clobber: .clobber-post

.clobber-pre:
# Add your pre 'clobber' code here...

.clobber-post: .clobber-impl
# Add your post 'clobber' code here...


# all
all: .all-post

.all-pre:
# Add your pre 'all' code here...

.all-post: .all-impl
# Add your post 'all' code here...


# build tests
build-tests: .build-tests-post

.build-tests-pre:
# Add your pre 'build-tests' code here...

.build-tests-post: .build-tests-impl
# Add your post 'build-tests' code here...


# run tests
test: .test-post

.test-pre:
# Add your pre 'test' code here...

.test-post: .test-impl
# Add your post 'test' code here...


# help
help: .help-post

.help-pre:
# Add your pre 'help' code here...

.help-post: .help-impl
# Add your post 'help' code here...



# include project implementation makefile
include nbproject/Makefile-impl.mk

# include project make variables
include nbproject/Makefile-variables.mk

#PROJECT-CONFIG
CND_DISTDIR=dist

.PHONY: .build-init


Makefile-Debug.mk

#
# Generated Makefile - do not edit!
#
# Edit the Makefile in the project folder instead (../Makefile). Each target
# has a -pre and a -post target defined where you can add customized code.
#
# This makefile implements configuration specific macros and targets.

# Environment
MKDIR=mkdir
CP=cp
GREP=grep
NM=nm
CCADMIN=CCadmin
RANLIB=ranlib
CC=gcc.exe
CCC=g++.exe
CXX=g++.exe
FC=gfortran.exe
AS=as.exe

# Macros
CND_PLATFORM=MinGW-Windows
CND_CONF=Debug
CND_DISTDIR=dist

# Include project Makefile
include Makefile

# Object Directory
OBJECTDIR=build/${CND_CONF}/${CND_PLATFORM}

# Object Files
OBJECTFILES= \
	${OBJECTDIR}/src/main.o \
	${OBJECTDIR}/src/test_thread_pool.o \
	${OBJECTDIR}/src/boost_thread_pool.o \
	${OBJECTDIR}/src/opra_curl.o
		
# C Compiler Flags
CFLAGS=

# CC Compiler Flags
CPPFLAGS=
CXXFLAGS=-g -Wall -MMD -MP -MF $@.d -m32 -D_UNICODE -D__QXWIN32__ \
 -I/E/software/project/tool/1.0.x/include \
 -I/E/software/Lib/tests/gtest-1.5.0/win32/release/static/include-compile \
 -I/E/software/Lib/tests/gtest-1.5.0/win32/release/static/include \
 -Iinclude \
 -I/E/software/Lib/common/boost-1.46.1/include   \
 -Iinclude/boost \
 -I/E/software/Lib/communications/curl-7.28.1/include


# Fortran Compiler Flags
FFLAGS=

# Assembler Flags
ASFLAGS=

LDLIBSOPTIONS=-L/E/software/Lib/tests/gtest-1.5.0/win32/release/static -L/E/software/project/tool/1.0.x/win32/share/Release -lgtest -lQX_Tool.1.0.0 -L/E/software/Lib/common/boost-1.46.1/win32/release/share/mt  -lboost_thread-mgw44-mt-1_46_1 -L/E/software/Lib/communications/curl-7.28.1/win32/release/share -lcurl-4

# Build Targets
.build-conf: ${BUILD_SUBPROJECTS}
	"${MAKE}"	-f nbproject/Makefile-Debug.mk dist/Debug/MinGW-Windows/threadpool.exe

dist/Debug/MinGW-Windows/threadpool.exe: ${OBJECTFILES}
	${MKDIR} -p dist/Debug/MinGW-Windows
	${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/threadpool.exe ${OBJECTFILES} ${LDLIBSOPTIONS} 

${OBJECTDIR}/src/main.o: nbproject/Makefile-${CND_CONF}.mk src/main.cpp
	${MKDIR} -p ${OBJECTDIR}/src
	${RM} $@.d
	$(COMPILE.cc) -o ${OBJECTDIR}/src/main.o src/main.cpp
	
${OBJECTDIR}/src/test_thread_pool.o: nbproject/Makefile-${CND_CONF}.mk src/test_thread_pool.cpp
	${MKDIR} -p ${OBJECTDIR}/src
	${RM} $@.d
	$(COMPILE.cc) -o ${OBJECTDIR}/src/test_thread_pool.o src/test_thread_pool.cpp
	
${OBJECTDIR}/src/boost_thread_pool.o: nbproject/Makefile-${CND_CONF}.mk src/boost_thread_pool.cpp
	${MKDIR} -p ${OBJECTDIR}/src
	${RM} $@.d
	$(COMPILE.cc) -o ${OBJECTDIR}/src/boost_thread_pool.o src/boost_thread_pool.cpp
	
${OBJECTDIR}/src/opra_curl.o: nbproject/Makefile-${CND_CONF}.mk src/opra_curl.cpp
	${MKDIR} -p ${OBJECTDIR}/src
	${RM} $@.d
	$(COMPILE.cc) -o ${OBJECTDIR}/src/opra_curl.o src/opra_curl.cpp
	
# Subprojects
.build-subprojects:

# Clean Targets
.clean-conf: ${CLEAN_SUBPROJECTS}
	${RM} -r build/Debug
	${RM} dist/Debug/MinGW-Windows/threadpool.exe

# Subprojects
.clean-subprojects:

# Enable dependency checking
.dep.inc: .depcheck-impl

include .dep.inc


//opra_curl.h

/*
 * opra_curl.h
 *
 *  Created on: 2013-3-14
 *      Author: hp
 */

#ifndef OPRA_CURL_H_
#define OPRA_CURL_H_

#include <stdlib.h>
#include <cstdio>
#include <stdio.h>
#include <vector>
#include <list>
#include <string.h>
#include <iostream>
#include <fstream>

#include <curl/curl.h>
#include <curl/easy.h>


//#include "VideoDownload/videodownload_info.h"

using namespace std;

typedef int (*VDownGetPercentage)(void* user_data, double icomplete, double itotal,
		int cur_file_index);

//暂时只用curl_proxy_http_type下载
enum CurlProxyType
{
	curl_proxy_null,
	curl_proxy_http_type, /* added in 7.10, new in 7.19.4 default is to use
	                           CONNECT HTTP/1.1 */
	curl_proxy_http_1_0,/* added in 7.19.4, force to use CONNECT
	                               HTTP/1.0  */
	curl_proxy_socks4,/* support added in 7.15.2, enum existed already
	                           in 7.10 */
	curl_proxy_socks5,/* added in 7.10 */
	curl_proxy_socks4a,/* added in 7.18.0 */
	curl_proxy_socks5_hostname/* Use the SOCKS5 protocol but pass along the*/
};

typedef struct ProxyData ProxyData;
struct ProxyData
{
	CurlProxyType proxy_type;
	char* proxy_addr;
	char* proxy_port;
	char* proxy_user;
	char* proxy_password;
};

struct MyBar
{
	VDownGetPercentage proc;
	CURL* handle;
	double lase_file_size;
	void* user_data;
};

int ConvertUint64ToChar(char* file_length, uint64_t file_size);

//暂停函数
int PauseDownload(CURL* handle);
//恢复下载函数
int ResumeDownload(CURL* handle);
//停止函数
int StopDownload(CURL* handle);
//下载到文件进度条回调函数
int MyProgressFunc(void *Bar, double t, /* dltotal */
double d, /* dlnow */
double ultotal, double ulnow);
//下载到内存进度条回调函数
int UrlProgressFunc(void *Bar, double t, /* dltotal */
double d, /* dlnow */
double ultotal, double ulnow);
//写到内存 的写函数
size_t Writer(void *data, size_t size, size_t nmemb, void* writerData);



class OpraCurl
{
public:
	//设置代理
	int SetCurlProxy(CURL* conn, ProxyData* proxy_data);

	//写到内存
	int DownloadHtml(char* url, string* p_buffer, ProxyData* proxy_data, int timeout,
			void* user_data, VDownGetPercentage GetPercentage);

	//下载到文件
	int DownloadVideo(void* self, const char* video_url,
			const char* target_file_path, int keep_down, ProxyData* proxy_data,
			void* user_data, VDownGetPercentage GetPercentage);

	OpraCurl();
	~OpraCurl();
};



#endif /* OPRA_CURL_H_ */

//opra_curl.cpp

/*
 * opra_curl.cpp
 *
 *  Created on: 2013-3-14
 *      Author: hp
 */
#include "opra_curl.h"

#include "tool/file/file_access.h"

//#include "common/common.h"
//#include "VideoDownload/videodownload_error.h"

int ConvertUint64ToChar(char* file_length, uint64_t file_size)
{
	#if defined(_UNICODE) || defined(UNICODE)
		sprintf(file_length, "%I64u-", file_size);
	#else
		sprintf(file_length, "%llu-", file_size);
	#endif

	return 0;
}

int PauseDownload(CURL* handle)
{
	curl_easy_pause(handle, CURLPAUSE_RECV);
	return 0;
}

int ResumeDownload(CURL* handle)
{
	curl_easy_pause(handle, CURLPAUSE_RECV_CONT);
	return 0;
}

int StopDownload(CURL* handle)
{
	return -1;
}

int MyProgressFunc(void *Bar, double t, /* dltotal */
double d, /* dlnow */
double ultotal, double ulnow)
{
	if ((int) (d * 100.0 / t) >= 0)
	{
		MyBar* my_bar = (MyBar*) Bar;
		VDownGetPercentage proc = (VDownGetPercentage) my_bar->proc;
		int ret = proc(my_bar->user_data, (d + my_bar->lase_file_size),
				(t + my_bar->lase_file_size), 0);
		if (-2 == ret)
		{
			return PauseDownload(my_bar->handle);
		}
		else if (1 == ret)
		{
			return ResumeDownload(my_bar->handle);
		}
		else if (-1 == ret)
		{
			return StopDownload(my_bar->handle);
		}
	}

	return 0;
}

int UrlProgressFunc(void *Bar, double t, /* dltotal */
double d, /* dlnow */
double ultotal, double ulnow)
{
//	if ((int) (d * 100.0 / t) >= 0)
//	{
	MyBar* my_bar = (MyBar*) Bar;
	VDownGetPercentage proc = (VDownGetPercentage) my_bar->proc;
	int ret = proc(my_bar->user_data, (d + my_bar->lase_file_size),
			(t + my_bar->lase_file_size), 0);
	if (-2 == ret)
	{
		return PauseDownload(my_bar->handle);
	}
	else if (1 == ret)
	{
		return ResumeDownload(my_bar->handle);
	}
	else if (-1 == ret)
	{
		return StopDownload(my_bar->handle);
	}
//	}

	return 0;
}

//写到内存
size_t Writer(void *data, size_t size, size_t nmemb, void* writerData)
{
	unsigned long sizes = size * nmemb;
	string* str_data = (string*) writerData;
	str_data->append((char*) data, sizes);
	return sizes;
}

//设置代理
int OpraCurl::SetCurlProxy(CURL* conn, ProxyData* proxy_data)
{
	if (!proxy_data)
	{
		return -1;
	}

	if (proxy_data->proxy_addr && strlen(proxy_data->proxy_addr) > 0
			&& proxy_data->proxy_port && strlen(proxy_data->proxy_port) > 0)
	{
		string curl_addr_port = string(proxy_data->proxy_addr) + ":"
				+ string(proxy_data->proxy_port);
		curl_easy_setopt(conn, CURLOPT_PROXY, curl_addr_port.c_str());

		string curl_user_password;
		if (proxy_data->proxy_user && proxy_data->proxy_password)
		{
			curl_user_password = string(proxy_data->proxy_user) + ":"
					+ string(proxy_data->proxy_password);
			curl_easy_setopt(conn, CURLOPT_PROXYUSERPWD,
					curl_user_password.c_str());
		}

		switch (proxy_data->proxy_type)
		{
		case curl_proxy_http_type:
			curl_easy_setopt(conn, CURLOPT_HTTPPROXYTUNNEL, 1L);
			curl_easy_setopt(conn, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
			break;
		case curl_proxy_http_1_0:
			curl_easy_setopt(conn, CURLOPT_PROXYTYPE, CURLPROXY_HTTP_1_0);
			break;
		case curl_proxy_socks4:
			curl_easy_setopt(conn, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
			break;
		case curl_proxy_socks5:
			curl_easy_setopt(conn, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
			break;
		case curl_proxy_socks4a:
			curl_easy_setopt(conn, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A);
			break;
		case curl_proxy_socks5_hostname:
			curl_easy_setopt(conn, CURLOPT_PROXYTYPE,
					CURLPROXY_SOCKS5_HOSTNAME);
			break;
		default:
			break;
		}
		return 0;
	}
	return -1;
}

int OpraCurl::DownloadHtml(char* url, string* p_buffer, ProxyData* proxy_data,
		int timeout, void* user_data, VDownGetPercentage GetPercentage)
{
	CURL* curl = curl_easy_init();
	MyBar* bar = (MyBar*) malloc(sizeof( MyBar));
	memset(bar, 0, sizeof(MyBar));
	if (curl)
	{
		curl_easy_setopt(curl, CURLOPT_URL, url);
		SetCurlProxy(curl, proxy_data);
		curl_easy_setopt(curl, CURLOPT_USERAGENT, "test-agent/1.0");
		curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Writer);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)p_buffer);
		if (GetPercentage)
		{
			bar->handle = curl;
			bar->proc = GetPercentage;
			bar->lase_file_size = 0;
			bar->user_data = user_data;
			// Install the callback function
			curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
			curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, bar);
			curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, UrlProgressFunc);
		}
		curl_easy_perform(curl);
		curl_easy_cleanup(curl);
	}

	free(bar);

	return 0;
}

int OpraCurl::DownloadVideo(void* self, const char* video_url,
		const char* target_file_path, int keep_down, ProxyData* proxy_data,
		void* user_data, VDownGetPercentage GetPercentage)
{
	int file_exist = QXIsFileExists(target_file_path);
	uint64_t file_size = 0;

	if (file_exist)
	{
		if (keep_down == 1)
		{
			file_size = QXGetFileSize(target_file_path);
		}
		else
		{
			::remove(target_file_path);
		}
	}

	FILE *file = QXfopen(target_file_path, "ab+");
	if (!file)
	{
		return -1;
	}
	// set up curl
	CURL* easyhandle = curl_easy_init();
	curl_easy_setopt( easyhandle, CURLOPT_URL, video_url);

	MyBar* bar = (MyBar*) malloc(sizeof( MyBar));
	memset(bar, 0, sizeof(MyBar));
	if (GetPercentage)
	{
		bar->handle = easyhandle;
		bar->proc = GetPercentage;
		bar->lase_file_size = file_size;
		bar->user_data = user_data;
		// Install the callback function
		curl_easy_setopt(easyhandle, CURLOPT_NOPROGRESS, 0);
		curl_easy_setopt(easyhandle, CURLOPT_PROGRESSDATA, bar);
		curl_easy_setopt(easyhandle, CURLOPT_PROGRESSFUNCTION, MyProgressFunc);
	}
	if (file_exist && keep_down == 1)
	{
		//curl_easy_setopt(easyhandle, CURLOPT_RESUME_FROM_LARGE, file_size);
		char num[70] =
		{ 0 };
		memset(num, 0, 70);
		ConvertUint64ToChar(num, file_size);

		string range = num;
		curl_easy_setopt(easyhandle, CURLOPT_RANGE, range.c_str());
	}
	if (proxy_data)
	{
		SetCurlProxy(easyhandle, proxy_data);
	}

	curl_easy_setopt(easyhandle, CURLOPT_VERBOSE, 1L);
	curl_easy_setopt( easyhandle, CURLOPT_WRITEDATA, file);
	curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 1);

	//1.注意,这里有返回值没处理.
	curl_easy_perform(easyhandle);
	fclose(file); //make sure to close file
	curl_easy_cleanup(easyhandle);
	free(bar);

	return 0;
}

OpraCurl::OpraCurl()
{
}
OpraCurl::~OpraCurl()
{
}


main.cpp

#include "boost_thread_pool.h"

#include <windows.h>

#include <boost/threadpool.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/smart_ptr.hpp>
#include <iostream>
#include <sstream>
#include <algorithm>
#include "threadpool.hpp"

#include "opra_curl.h"

using namespace std;
using namespace boost::threadpool;


boost::mutex m_io_monitor;

string g_diff;

int PrintfProcessForMulThread(void* user_data, double complete_num, double total_num,
		int cur_file_index)
{

	cout << "complete:" << complete_num << "B\ttotal:" << total_num
			<< "B\tcur_file_index:" << boost::this_thread::get_id() << endl;

	return 0;
}


class MyTest
{
public:
	MyTest(){m_index = 0; m_max = 3;}
	~MyTest(){}


	void Run()
	{

		for(; m_index < m_max ; m_index++)
		{
			Sleep(3000);
			cout<<boost::this_thread::get_id()<<m_index<<endl;
		}
	}
private:
	int m_index;
	int m_max;
};



void Run2(string str)
{
	//char ch = char(rand());
	g_diff.append("1");
	ProxyData* proxy_data = (ProxyData*)calloc(1, sizeof(ProxyData));
	proxy_data->proxy_type = curl_proxy_http_type;
	proxy_data->proxy_addr = "192.168.0.1";
	proxy_data->proxy_port = "808";
	OpraCurl down;
	down.DownloadVideo(NULL, "www.istonsoft.com/downloads/iston-video-converter.exe",
			str.append(g_diff).append(".exe").c_str(), 1, proxy_data, NULL, PrintfProcessForMulThread);
	free(proxy_data);
}

int main (int argc, char * const argv[])
{
	string dir = "C:\\ll\\";//QXGetRunDirectory(argv[0]);
	pool tp;
	tp.size_controller().resize(5);

	int step = 1;
	for(; step <= 10; step++)
	{
//		boost::shared_ptr<MyTest > job(new MyTest());
//		//tp->schedule(prio_task_func(5, boost::bind(&merge_job<image>::run, job)));
//		schedule(tp, boost::bind(&MyTest::Run, job));
//		// schedule(tp, job);
		schedule(tp, boost::bind(&Run2, dir));
	}

	tp.wait();	// wait until all partitions are sorted

	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值