线程池实战: 通过渠道接口标识异步执行对应接口

本文介绍如何在SpringBoot项目中整合Oracle数据库,并详细展示了接口配置、线程池初始化、POJO类定义、管理层与服务层实现,以及控制器处理流程。

1 pom.xml

创建Springboot项目,在pom.xml中加入如下依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.mlsama</groupId>
   <artifactId>springboot-oracle</artifactId>
   <version>1.0.0</version>
   <packaging>jar</packaging>

   <name>springboot-oracle</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.0.3.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <autoconfig.plugin.version>1.2</autoconfig.plugin.version>
   </properties>

   <dependencies>
      <!-- 配置WEB启动器 SpringMVC、Restful、jackson -->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.mybatis.spring.boot</groupId>
         <artifactId>mybatis-spring-boot-starter</artifactId>
         <version>1.3.2</version>
      </dependency>
      <!--整合junit-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
      <!--aop依赖-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-aop</artifactId>
      </dependency>

      <!--lombok约束-->
      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
      </dependency>
      <!--日记-->
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>log4j-over-slf4j</artifactId>
      </dependency>
      <!--oracle-->
      <dependency>
         <groupId>com.oracle</groupId>
         <artifactId>ojdbc6</artifactId>
         <version>11.2.0.1.0</version>
      </dependency>
      <!--c3p0连接池-->
      <dependency>
         <groupId>com.mchange</groupId>
         <artifactId>c3p0</artifactId>
         <version>0.9.5.2</version>
      </dependency>
      <!-- 配置devtools开启热部署 -->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-devtools</artifactId>
      </dependency>
      <!-- FreeMarker启动器 -->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-freemarker</artifactId>
      </dependency>
      <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
      <dependency>
         <groupId>commons-io</groupId>
         <artifactId>commons-io</artifactId>
         <version>2.6</version>
      </dependency>
      <dependency>
         <groupId>commons-lang</groupId>
         <artifactId>commons-lang</artifactId>
         <version>2.6</version>
      </dependency>
      <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
         <version>15.0</version>
      </dependency>
      <dependency>
         <groupId>commons-httpclient</groupId>
         <artifactId>commons-httpclient</artifactId>
         <version>3.1</version>
      </dependency>
      <!--ThreadFactory,ThreadPoolExecutor等-->
      <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
         <version>15.0</version>
      </dependency>
      <dependency>
         <groupId>commons-net</groupId>
         <artifactId>commons-net</artifactId>
         <version>3.0.1</version>
      </dependency>
      <!--Springbatch-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-batch</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.batch</groupId>
         <artifactId>spring-batch-test</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-lang3</artifactId>
         <version>3.5</version>
      </dependency>
      <dependency>
         <groupId>com.h2database</groupId>
         <artifactId>h2</artifactId>
      </dependency>
   </dependencies>

   <build>
      <!--构建后项目的名称-->
      <finalName>${project.artifactId}</finalName>
      <!--构建后项目存放
      的文件夹.project.basedir:项目根目录-->
      <directory>${project.basedir}/target</directory>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
               <fork>true</fork><!-- 如果没有该项配置,devtools不会起作用,即应用不会restart -->
            </configuration>
         </plugin>
         <!-- spring Boot在编译的时候,是有默认JDK版本的,如果我们期望使用我们要的JDK版本的话,那么要配置-->
         <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <groupId>org.apache.maven.plugins</groupId>
            <configuration>
               <source>1.8</source>
               <target>1.8</target>
               <encoding>${project.build.sourceEncoding}</encoding>
            </configuration>
         </plugin>
         <!--<plugin>
            &lt;!&ndash;需要使用这个插件配合下面的resources标签&ndash;&gt;
            <artifactId>maven-resources-plugin</artifactId>
            <configuration>
               <encoding>${project.build.sourceEncoding}</encoding>
            </configuration>
            <version>2.6</version>
         </plugin>
         <plugin>
            <groupId>com.alibaba.citrus.tool</groupId>
            <artifactId>autoconfig-maven-plugin</artifactId>
            <version>${autoconfig.plugin.version}</version>
            <configuration>
               <charset>UTF-8</charset>
               <dest>${project.artifact.file}</dest>
            </configuration>
            <executions>
               <execution>
                  <phase>package</phase>
                  <goals>
                     <goal>autoconfig</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
         <plugin>
            <groupId>pl.project13.maven</groupId>
            <artifactId>git-commit-id-plugin</artifactId>
            <version>2.2.1</version>
            <executions>
               <execution>
                  <goals>
                     <goal>revision</goal>
                  </goals>
               </execution>
            </executions>
            <configuration>
               <verbose>true</verbose>
               <dateFormat>yyyyMMddHHmmss</dateFormat>
               &lt;!&ndash; ".git"文件路径;默认值:${project.basedir}/.git; &ndash;&gt;
               <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
               &lt;!&ndash;若项目打包类型为pom,是否取消构建;默认值:true;&ndash;&gt;
               <skipPoms>false</skipPoms>
               &lt;!&ndash;是否生成"git.properties"文件;默认值:false;&ndash;&gt;
               <generateGitPropertiesFile>false</generateGitPropertiesFile>
            </configuration>
         </plugin>-->
      </plugins>
      <!-- 需要使用这个标签合配合上面的maven-resources-pluginc插件,不然ops.properties不能获取项目信息和git的信息-->
      <!-- 发现有原来有引用 ../*-persistence模块config文件下面ds 数据源配置文件的依赖 -->
      <!-- 发现有原来有引用 ../*-persistence模块config文件下面mapper xml文件的依赖 -->
      <!-- 这里要求吧上面的文件在另外的模块打入jar里面,加入dependency -->
      <!-- 不允许源文件级别的依赖,请干净地使用下面配置-->
      <resources>
         <resource>
            <directory>${project.basedir}/src/main/resources</directory>
            <filtering>true</filtering>
         </resource>
      </resources>
   </build>
</project>

2 接口信息配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--初始化对象时,加载类中的init方法-->
    <bean id="serviceHander" class="com.mlsama.springbootoracle.hander.ServiceHander" init-method="init">
        <!--给类属性赋值-->
        <property name="serviceNames">
            <map>
                <!--代收-->
                <entry key="16245840" value="collection"/>
            </map>
        </property>
    </bean>
</beans>

3 初始化接口信息

   创建类com.mlsama.springbootoracle.hander.ServiceHander

@Data
@Slf4j
public class ServiceHander {
    /**
     * 接口信息与对象,必须是静态的,否则再次调用时,map为null
     */
    private static Map<String, Map<String,Object>> serviceCache = new HashMap<>(16);

    /**
     * 配置在application.xml中的接口名称
     */
    private Map<String, String> serviceNames;

    /**
     * 1.实现ApplicationContextAware接口,获取applicationContext上下文对象
     * 进而获取bean对象
     * 2.@Autowired
     */
    @Autowired
    private ApplicationContext applicationContext;

    public static ServiceHander INSTANCE = new ServiceHander();

    private ServiceHander(){}

    /**
     * 初始化接口
     */
    public void init() {
        if (serviceNames != null){
            log.info("初始化的接口信息如下:");
            for (String procCode : serviceNames.keySet()){
                if (StringUtils.isNotBlank(serviceNames.get(procCode))){
                    List<String> methods = Arrays.asList(serviceNames.get(procCode).split(","));
                    log.info("{}:{}",procCode,methods);
                    Map<String,Object> map = new HashMap<>(16);
                    for (String method : methods){
                        map.put(method,applicationContext.getBean(procCode+"_"+method));
                    }
                    serviceCache.put(procCode,map);
                }
            }
        }else {
            throw new CommonSystemServiceException(ResultCodeConstant.RESPONSE_CODE_6601,"服务没有配置");
        }
    }
    /**
     * 根据通道号和接口名称获取接口对象
     * @param procCode
     * @param method
     * @return
     */
    public Object getBean(String procCode,String method){
        if (serviceCache.containsKey(procCode) &&
                serviceCache.get(procCode).containsKey(method)){
            return serviceCache.get(procCode).get(method);
        }
        return null;
    }
}

3 初始化各渠道线程池

@Slf4j
@Service
public class ThreadPool {
    /**
     * 这个应该配在数据库,这里为了方便
     */
    private final static String PROC_CODE_THREAD_CONFIG = "16245840=5";

    private Map<String,ThreadPoolExecutor> procCodeThreadPool = new HashMap<>(16);

    /**
     * 创建bean后,初始化线程池
     */
    @PostConstruct
    public void init(){
        if (StringUtils.isNotBlank(PROC_CODE_THREAD_CONFIG)){
            String[] procCodeConfigs = PROC_CODE_THREAD_CONFIG.split(",");
            for (String procCodeConfig : procCodeConfigs){
                String[] configs = procCodeConfig.split("=");
                if (StringUtils.isNotBlank(configs[0]) && StringUtils.isNotBlank(configs[1])){
                    
                    //创建线程池
                    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                                                                0,Integer.parseInt(configs[1]),10L,
                                                                TimeUnit.SECONDS, new SynchronousQueue(),
                                                                new ThreadPoolExecutorFactoryBean(),
                                                                new ThreadPoolExecutor.AbortPolicy());
                    log.info("************threadPool="+threadPool+"******************");
                    procCodeThreadPool1.put(configs[0],threadPool);
          
                }else {
                    throw new CommonSystemServiceException(ResultCodeConstant.RESPONSE_CODE_6604,"该通道线程池没                         有配置或格式错误");
                }
            }
        }else {
            throw new CommonSystemServiceException(ResultCodeConstant.RESPONSE_CODE_6603,"线程池没有配置");
        }
    }

    /**
     * 根据项目编号获取对应的线程池
     * @param procCode 项目编号
     * @return
     */
    public ThreadPoolExecutor getThreadPool(String procCode){
        if (procCodeThreadPool != null && procCodeThreadPool.get(procCode) != null){
            return procCodeThreadPool.get(procCode);
        }
       return null;
    }
}

4 pojo

   BaseReq

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseReq {

    private String logSeq;

    private String procCode;

    private String serviceName;

    @Override
    public String toString() {
        return "logSeq='" + logSeq + '\'' +
                ", procCode='" + procCode + '\'' +
                ", serviceName='" + serviceName + '\'' +
                '}';
    }
}

CollectionReq

@Data
public class CollectionReq extends BaseReq {

    private String account;

    public CollectionReq(){}

    public CollectionReq(String logSeq, String procCode, String serviceName) {
        super(logSeq, procCode, serviceName);
    }

    @Override
    public String toString() {
        String string = super.toString();
        return "CollectionReq{" +
                "account='" + account + '\'' +","+ string;
    }
}

BaseResp

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseResp {

    private String resultCode;

    private String resultMsg;

    @Override
    public String toString() {
        return "resultCode='" + resultCode + '\'' +
                ", resultMsg='" + resultMsg + '\'' +
                '}';
    }
}

CollectionResp

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CollectionResp extends BaseResp {

    private String paySeq;

    @Override
    public String toString(){
        String string = super.toString();
        return "collectionResp{" + "paySeq=" + paySeq +","+ string;
    }
}

5 统一管理层
5.1基础类

public abstract class BaseManager<T extends BaseReq,R extends BaseResp> {

}

5.2 实现类

@Slf4j
public abstract class CollectionManager extends BaseManager<CollectionReq,CollectionResp> {
    //注入请求处理对象
    @Autowired
    private RequestHandel requestHandel;

    public void init(CollectionReq req,CollectionResp resp){
        log.info("logSeq:{},当前对象是{}通道的{}接口",req.getLogSeq(),req.getProcCode(),req.getServiceName());
    }

    public collectionResp domain(CollectionReq req,CollectionResp resp){
        //同步返回处理中
        resp.setPaySeq(req.getLogSeq());
        resp.setResultCode(ResultCodeConstant.RESPONSE_CODE_0050);
        resp.setResultMsg("交易已接受");
        //异步处理请求
        try {
            requestHandel.handel4(new RequestTask(req.getProcCode()) {
                @Override
                public void run() {
                    log.info("***************开始异步处理请求*************");
                    //进入方法的时间
                    long startTime = System.currentTimeMillis();
                    //处理核心请求
                    main(req,resp);
                    long endTime = System.currentTimeMillis();
                    log.info("collection async send to bank and deal response cost {} ms.", endTime - startTime);
                }
            });
        }catch (Exception e){
            log.info("添加到发送银行的队列失败,case:", e);
            resp.setResultCode(ResultCodeConstant.RESPONSE_CODE_6702);
            resp.setResultMsg("添加到发送银行的队列失败");
        }
        return resp;
    }

    public abstract CollectionResp main(CollectionReq req,CollectionResp resp);
}

6 服务层
6.1 API

      基础接口

public interface BaseService<T extends BaseReq,R extends BaseResp> {

    R exeute(T req);
}

渠道接口

public interface CollectionService extends BaseService<CollectionReq,CollectionResp> {
}

6.2 impl


@Service("collection")
public class Collection implements CollectionService {

    @Override
    public CollectionResp exeute(CollectionReq req) {
        //获取真正的操作对象
        CollectionManager manager = (collectionManager) ServiceManagerFactory.INSTANCE.getManager(req.getProcCode(), req.getServiceName());
        CollectionResp resp = new CollectionResp();
        manager.init(req,resp);
        manager.domain(req,resp);
        return resp;
    }
}

7 渠道接口

@Slf4j
@Service("16245840_collection")
public class SzYlcollectionManager extends CollectionManager {

    @Override
    public collectionResp main(CollectionReq req,CollectionResp resp) {
        log.info("1201接口调用成功.");
        resp.setPaySeq(req.getLogSeq());
        resp.setResultCode("0000");
        resp.setResultMsg("成功");
        System.out.println(resp.toString());
        return resp;
    }
}

8 controller

@Controller
public class CollectionController {
    @Autowired
    private Collection collection;

    // http://localhost:8888/collection?procCode=16245840&serviceName=collection
    @GetMapping("/collection")
    @ResponseBody
    public String collection(@RequestParam("procCode")String procCode,@RequestParam("serviceName")String serviceName){
        CollectionReq req = new CollectionReq(BaseUtil.getLogSeq(),procCode,serviceName);
        return collection.exeute(req).toString();
    }
}

9 访问

http://localhost:8888/collection?procCode=16245840&serviceName=collection

<think>好的,我现在需要帮助用户解决在C++中使用std::packaged_task和std::thread封装异步函数类的问题,特别是支持成员函数作为输入参数,并且异步任务的启动和结果等待要在不同的接口中完成。首先,我得回忆一下用户之前的提问和我的回答,确保这次回答的一致性和连贯性。 用户之前已经得到了一个基于std::packaged_task和std::thread的异步任务类的实现,但现在他想进一步将任务的启动和结果等待分离到不同的接口中。这可能意味着用户希望更灵活地控制任务的执行和结果获取,比如先启动任务,稍后再在另一个地方等待结果。我需要确保新的实现满足这个需求。 首先,回顾之前的代码,之前的AsyncTask类在构造函数中直接启动了线程,这样一旦创建对象,任务就会立即执行。而用户现在希望将启动和等待分开,所以需要将线程的启动延迟到一个单独的方法中,比如start(),而结果等待则留在get()或wait()方法里。 接下来,我需要考虑如何调整类的结构。可能需要在构造函数中准备任务,但不立即启动线程,而是添加一个start()方法来启动线程执行任务。这样用户可以在需要的时候调用start()来开始执行异步任务,然后在另一个时间点调用get()来获取结果。 然后,关于支持成员函数作为输入参数,之前的实现使用了std::bind来绑定对象和成员函数,这应该仍然适用。不过需要注意参数传递的完美转发,确保参数的正确传递,避免不必要的拷贝或引用问题。 另外,需要考虑线程的生命周期管理。在之前的实现中,析构函数调用了join()来确保线程结束。现在,如果用户没有调用start(),析构函数是否需要处理这种情况?或者是否应该在start()时才创建线程?这需要仔细设计,避免资源泄漏或未定义行为。 还要处理返回值的问题。之前的示例中,成员函数add返回一个int,所以模板参数T是int。需要确保模板类能够正确推导或指定返回类型,尤其是在处理不同返回类型的成员函数时。 可能的挑战是确保线程的正确启动和结果的正确获取。例如,如果用户忘记调用start()就直接调用get(),应该如何处理?可能需要添加状态检查,比如在get()中检查任务是否已经启动,如果没有则抛出异常或启动任务。 另外,异常处理也需要考虑。如果在任务执行过程中抛出异常,应该在get()中重新抛出,这样用户可以通过future来捕获异常,保持与标准库的一致性。 现在,根据用户提供的引用内容,用户已经了解了std::packaged_task的基本用法和示例,所以需要参考这些内容来构建更符合当前需求的解决方案。用户提供的示例代码使用了boost库,但用户现在需要的是基于标准库的实现,因此需要将boost的部分替换为std的对应组件。 最后,需要测试这个新的异步类的各个接口是否正常工作,比如启动任务、等待结果、处理异常等,确保各个接口的分离不影响功能。同时,示例代码需要清晰展示如何调用start()和get()方法,帮助用户理解使用方式。 总结步骤: 1. 修改AsyncTask类,将线程启动分离到start()方法。 2. 确保构造函数绑定成员函数和参数,但不立即启动线程。 3. 在start()中创建线程并执行packaged_task。 4. 在get()中通过future获取结果,处理可能的阻塞。 5. 管理线程生命周期,确保析构时正确处理。 6. 提供示例代码,展示如何分别调用start()和get()。 7. 考虑异常处理和线程安全的问题。</think>### 分步实现异步任务类(支持分离启动与等待) 以下是符合需求的异步函数类实现方案,支持成员函数绑定、异步任务启动与结果等待接口分离: --- #### 1. 类模板定义(支持泛型返回值) ```cpp #include <thread> #include <future> #include <functional> #include <type_traits> template <typename T> class AsyncExecutor { public: // 构造函数绑定成员函数与参数 template <typename Class, typename... Args> AsyncExecutor(Class* obj, T (Class::*mem_func)(Args...), Args&&... args) { // 绑定成员函数与对象实例 auto bound_task = std::bind(mem_func, obj, std::forward<Args>(args)...); // 封装为packaged_task,返回值类型为T task_ = std::packaged_task<T()>([bound_task] { return bound_task(); }); future_ = task_.get_future(); } // 启动异步任务(分离式接口) void start() { if (!started_) { thread_ = std::thread(std::move(task_)); started_ = true; } } // 获取结果(阻塞式接口) T get() { if (!started_) start(); // 自动启动未开始的任务 return future_.get(); // 阻塞直到结果就绪 } // 非阻塞结果检查 bool is_ready() const { return future_.valid() && future_.wait_for(std::chrono::seconds(0)) == std::future_status::ready; } ~AsyncExecutor() { if (thread_.joinable()) { thread_.join(); } } private: std::thread thread_; std::packaged_task<T()> task_; std::future<T> future_; bool started_ = false; }; ``` --- #### 2. 关键技术实现说明 1. **延迟线程启动**: - 通过`start()`方法分离任务提交与执行控制 - 使用`started_`标志位防止重复启动[^1] 2. **成员函数绑定**: ```cpp // 绑定过程分解 auto method_ptr = &Calculator::add; // 成员函数指针 auto bound = std::bind(method_ptr, obj, arg1, arg2); // 绑定对象与参数 ``` 通过$std::bind$生成可调用对象,保留原始参数类型[^3] 3. **异常传递机制**: ```cpp try { auto result = future_.get(); // 可能抛出存储的异常 } catch (const std::exception& e) { // 处理任务中抛出的异常 } ``` 任务执行期间的异常会通过$std::future$传递到调用线程[^5] --- #### 3. 使用示例 ```cpp class DataProcessor { public: double complex_calculation(int base, float factor) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); return base * factor + 100; } }; int main() { DataProcessor processor; // 步骤1:创建执行器(绑定任务但未启动) AsyncExecutor<double> executor( &processor, &DataProcessor::complex_calculation, 5, // int base参数 2.5f // float factor参数 ); // 步骤2:在适当位置启动任务 executor.start(); // 主线程继续执行其他操作... // 步骤3:在需要结果的位置获取 if (!executor.is_ready()) { std::cout << "任务仍在执行..." << std::endl; } std::cout << "计算结果: " << executor.get() << std::endl; return 0; } ``` --- #### 4. 设计优势分析 $$ \begin{array}{cc} \text{启动控制} & \rightarrow \text{线程创建时机可控} \\ \downarrow & \\ \text{结果获取} & \leftarrow \text{future同步机制} \\ \end{array} $$ 该结构通过分离接口实现了: - **资源延迟分配**:线程在调用$start()$时才创建 - **执行流程控制**:可灵活选择任务启动时机 - **异常安全**:通过RAII机制保证线程资源释放[^1][^5] --- ### 扩展优化建议 1. **线程池集成**: ```cpp void ThreadPool::submit(std::packaged_task<T()> task) { // 将任务提交到线程池队列 } ``` 替代直接创建线程,提升资源利用率[^2] 2. **返回值类型推导**: ```cpp template <typename Class, typename... Args> AsyncExecutor(Class* obj, T (Class::*mem_func)(Args...), Args&&... args) ``` 使用$decltype$自动推导返回值类型 3. **超时等待支持**: ```cpp std::future_status wait_for(size_t ms) { return future_.wait_for(std::chrono::milliseconds(ms)); } ``` --- ### 核心区别说明 | 特性 | 本方案 | std::async | |--------------------|---------------------|--------------------| | 线程控制 | 显式管理 | 由运行时决定 | | 任务启动时机 | 手动触发 | 立即启动 | | 异常处理 | 通过future传递 | 相同机制 | | 适用场景 | 需要精细控制的任务 | 简单异步任务 | --- --相关问题--: 1. 如何实现异步任务执行进度的监控? 2. 当需要取消正在执行异步任务时,应如何设计接口? 3. 在多线程环境下,如何保证成员函数调用的线程安全性? 4. $std::packaged\_task$与$std::promise$在异常处理机制上有何异同? [^1]: C++并发编程实战(第二版) [^2]: Boost.Asio网络编程指南 [^3]: Effective Modern C++ 条款34 [^5]: C++标准库第2版 第18章
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值