windows线程API 及多线程

Windows多线程相关API 如果想精通WIN下的多线程编程,需要很好的线程原理的基础,但是如果只想初步应用WIN下的多线程的API,这篇文单还是有用的,我目前的情况,也仅是初步使用,而且够用HANDLE WINAPI CreateThread( _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dw 阅读详情
原文:http://blog.youkuaiyun.com/lcj8/article/details/1891404 

 在Windows的多线程编程中,创建线程的函数主要有CreateThread和_beginthread(及_beginthreadex)。
 
CreateThread 和 ExitThread
 
    使用API函数CreateThread创建线程时,其中的线程函数原型:
        DWORD WINAPI ThreadProc(LPVOID lpParameter);
在线程函数返回后,其返回值用作调用ExitThread函数的参数(由系统隐式调用)。可以使用GetExitCodeThread函数获得该线程函数的返回值。
 
    当线程函数的起始地址无效(或者不可访问)时,CreateThread函数仍可能成功返回。如果该起始地址无效,则当线程运行时,异常将发生,线程终止。并返回一个错误代码。
 
    使用CreateThread创建的线程具有THREAD_PRIORITY_NORMAL的线程优先级。可以使用GetThreadPriority和SetThreadPriority函数获取和设置线程优先级值。
 
    系统中的线程对象一直存活到线程结束,并且所有指向它的句柄都通过调用CloseHandle关闭后。
 
_beginthread 和 _endthread (_beginthread & _endthread)
 
    对于使用C运行时库里的函数的线程应该使用_beginthread和_endthread这些C运行时函数来管理线程,而不是使用CreateThread和ExitThread。否则,当调用ExitThread后,可能引发内存泄露。
 
    在使用_beginthread或者_beginthreadex创建线程时,应该包含头文件<process.h>,并且需要设置多线程版 本的运行时库。「Project Settings」--> 「C/C++」-->「Category」-->「Code Generation」-->「Use Run-Time Library」-->「Multithreaded」和「Debug Multithreaded」。这相当于给编译添加了一个编译选项/MT,使编译器在编译时在.obj文件中使用libcmt.lib文件名而不是 libc.lib。连接器使用这个名字与运行时库函数连接。
 
    可以调用_endthread和_endthreadex显示式结束一个线程。然而,当线程函数返回时,_endthread和_endthreadex 被自动调用。endthread和_endthreadex的调用有助于确保分配给线程的资源的合理回收。_endthread自动地关闭线程句柄,然而 _endthreadex却不会。因此,当使用_beginthread和_endthread时,不需要显示调用API函数CloseHandle式关 闭线程句柄。该行为有别于API函数ExitThread的调用。_endthread和_endthreadex回收分配的线程资源后,调用 ExitThread。
 
    当_beginthread和_beginthreadex被调用时,操作系统自己处理线程栈的分配。如果在调用这些函数时,指定栈大小为0,则操作系统 为该线程创建和主线程大小一样的栈。如果任何一个线程调用了abort、exit或者ExitProcess,则所有线程都将被终止。

 
同步与互斥
 
    在一个进程中,多个线程可以使用同一函数作为其线程函数,或者多个线程函数直接或间接调用同一个函数。此时,该函数中使用的自动(局部)变量(存储于栈 上)在每个线程中都有一个独立的对象,互不干扰(虽然是同一函数,但被不同的线程所调用,可以把它们想象成不同的函数)。但所有静态变量却是共享的(包括 函数内静态变量)。此时就要注意该静态对象的同步与互斥了,可以使用信号和临界区来实现。
 
    当辅助线程正在绘制它的输出时,可能主线程刚好收到一个WM_PAINT或者WM_ERASEBKGND消息。这时,可以使用临界区来避免两个线程在同一 窗口上同时绘画所带来的任何可能问题。但实验表明,Windows 98是串行地访问图形绘画函数的,也就是说,在一个线程未完成绘制前,另一个线程不是能够开始绘制的。但Windows 98文档对一个地方未串行化给予了警告,那就是在实用GDI对象时,例如画笔、画刷、字体、位图、区域和调色板。因此,这里就需要使用临界区来避免可能的 问题。当然,更好的方式是不在线程间共享GDI对象。
 
    对于多线程编程,最好的方式是主线程负责创建程序的所有窗口,包括这些函数的窗口过程,并处理传给这些窗口的消息;而辅助线程执行后台作业或者冗长的作业。
 
    通常,我们使用WM_TIMER消息实现动画。但是如果辅助线程不创建一个窗口,它就无法接收消息。而如果没有延时,动画总是运行得太快。这时,我们可以 使用Sleep函数。线程调用Sleep函数来挂起它自己。传给Sleep的参数为0时,致使线程放弃它剩余的时间片。当一个线程调用Sleep挂起它自 己时,程序中其它线程仍继续运行,不受影响。通常,不应该在主线程中使用Sleep函数,因为它会影响消息处理速度。
 
临界区
 
    临界区实现的是互斥技术。在任何时刻,只有一个线程能进入临界区。只有在该线程离开临界区后,其它线程才能进入。临界区对象不能被移动 或者拷贝,进程也不能够修改该对象,而必须把它看作逻辑上不透明的(小黑箱)。使用由Win32 API提供的临界区函数来管理临界区对象。
 
    要使用临界区,首先需要定义一个临界区对象,此时,进程负责分配相应内存:
        CRITICAL_SECTION cs;
 
    然后,临界区对象必须由程序中某个线程初始化:
        InitializeCriticalSection(&cs);
 
    当初始化完该临界区对象后,线程可以调用下面的函数进入临界区:
        EnterCriticalSection (&cs);
 
    进入临界区后,该线程被认为拥有该入临界区对象。因此,其它线程调用EnterCriticalSection想进入该入临界区时,会被挂起。赶到拥有临 界区对象的线程离开临界区后,它才有机会获得该临界区对象。一旦一个线程拥有临界区,那么它可以再调用EnterCriticalSection或者 TryEnterCriticalSection而不会阻塞它自己的执行。这防止了一个线程因等待它自己所拥有的临界区而出现死锁。 (TryEnterCriticalSection与TryEnterCriticalSection的区别:前者无论是否获得临界区,都立即返回;而后 者在获得临界区前一直处理阻塞状态。TryEnterCriticalSection可以通过函数的返回值判断是否获得临界区,如果没有,可以做其它事 情,而不是处于等待状态。)
 
    离开临界区:
        LeaveCriticalSection(&cs);
 
    当临界区不再需要时,可将其删除,从而释放相应系统资源:
        DeleteCriticalSection (&cs);
 
    使用临界区有一个限制,它只能用于同一进程内的线程间的互斥。而在某些情况下,需要协调两个不同进程对同一资源的共享(如共享内存)。此时,已不能再使用 临界区做到,需要借助于互斥对象(mutex object)来实现(注:mutex是一个合成词[mutual exclusion])。
        
事件信号
 
    当需要线程间的同步时,可以使用信号机制,这里介绍Windows编程中的事件信号。
 
    HANDLE CreateEvent(
        LPSECURITY_ATTRIBUTES lpEventAttributes,
                            // pointer to security attributes
        BOOL bManualReset,  // flag for manual-reset event
        BOOL bInitialState, // flag for initial state
        LPCTSTR lpName      // pointer to event-object name
    );
创 建一个有名或无名事件对象。第一个参数lpEventAttributes:如果该事件不被子进程所继承,则通常置为NULL。第二个参数 bMenualReset:如果为TRUE,你必须手动调用ResetEvent函数设置事件状态为nonsignaled状态;如果为FALSE,则系 统会在一个等待线程就绪后(即一个WaitForSingleObject返回后)自动重置为nonsignaled状态。第三个参数 bInitialState:如果为TRUE,则初始状态为signaled;否则为nonsignaled。第四个参数lpName:指向事件对象的名 字(如果为NULL,则为无名事件对象)。如果不为NULL,则首先搜索现有的对象是否与该名字一致,再进一步处理。如果该对象不需要共享的话,一般置为 NULL。
 
    BOOL SetEvent(HANDLE hEvent);   // 设置hEvent事件状态为signaled。
    BOOL ResetEvent(HANDLE hEvent); // 设置hEvent事件状态为nonsignaled。
 
    等待函数。Win32 API提供了一组等待函数来允许线程阻塞它自己的执行。分为三类等待函数:1)单对象;2)多对象;3)alertable。等待函数不会返回,除非指定 的条件满足。等待函数的类型决定了要检验的条件。当一个等待函数被调用时,它首先检查条件是否满足。如果不满足,则该线程进入等待状态,进入相应事件的等 待队列,直到相应信号将其唤醒。这里重点介绍WaitForSingleObject函数。
 
    DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
当等待的对象为signaled状态或者超时时,该函数返回。该函数不仅用于Event对象,还可用于其它对象,
如Job、Mutex、Semphore、Thread等等。另外,对于创建了窗口的线程,不要用这个函数,否则容易发生死锁,此时应考虑使用MsgWaitForMultipleObjects 或者MsgWaitForMultipleObjectsEx。
 
    最后,使用CloseHandle函数来关闭句柄。当进程结束时,系统自动关闭句柄。当被关闭的句柄是该事件对象的最后一个句柄时,该对象被销毁。
 
线程局部存储(TLS)
   
    一个多线程程序中,全局变量(及分配的内存)被所有线程所共享。函数的静态局部变量也被所有使用该函数的线程所共享。一个函数中的自动变量对每一个线程是唯一的,因为它们存储于堆栈上,而每个线程都有
他们自己的堆栈。有时,我们需要对每一个线程唯一的持续性存储。例如,C函数strtok就需要这种存储。不幸的是,C语言不支持这种变量。但 是Windows提供了四个API函数来实现这种机制。我们把这种存储称为线程局部存储(TLS,Thread Local Storage)。
 
    首先,定义一个结构,把对每个线程唯一的数据包含在该结构中。例如:
    typedef struct {
        int one;
        int two;
    } DATA, *PDATA;
 
    然后,主线程调用TlsAlloc函数来为进程获得一个TLS索引:tlsIndex = TlsAlloc();
该TLS索引可以存储于一个全局变量或者通过线程函数的参数传递给其它线程。
    每个需要使用该TLS索引的线程,先动态分配内存,然后调用TlsSetValue函数将该内存关联到该TLS索引(及该线程): TlsSetValue(tlsIndex, GlobalAlloc(GPTR, sizeof(DATA));
    此时,线程直接或间接调用的函数可以通过如下方式获得该线程的TLS存储区域:
    PDATA pdata;
    pdata = (PDATA) TlsGetValue(tlsIndex);
此时,就可以使用该线程的TLS存储区的变量了。

    当线程函数终止时,它应该释放它所分配的动态空间: GlobalFree(TlsGetValue(tlsIndex));
    当所有使用TLS的线程都终止后,主线程应当释放该TLS存储空间: TlsFree(tlsIndex);
 
    常量TLS_MINIMUM_AVAILABLE定义了每个进程可用的TLS索引的最小值(>=64)。
 
    TLS可以以一种更简单的方式使用,那就是通过Winodws对C所作的扩展关键字__declspec和扩展存储类型修饰符thread。例如:
    __declspec(thread) int global_tls_i = 1;        // 在函数外部,声明一个TLS变量
    __declspec(thread) static int local_tls_i = 2;  // 在函数内部声明一个静态TLS变量
    
《Windows API每日一练》19.2 Windows多线程 这个窗口过程很简单.。在处理WM_CREATE消息时,它设定该结构的hwnd和cyChar字段,调用_beginthread函数创立一个使用Threadl函数的新线程并且传递给新线程一个指向该PARAMS结构的指针。这个实现看起来很好:如果一个程序在花很长时间处理一条消息,那么当鼠标在该程序的窗口上时,鼠标指针会显示为沙漏,而当它在另一个程序的窗口上时,就变成正常的箭头了。在主线程中,我们创建一个新的线程,等待线程结束后,使用GetExitCodeThread函数获取线程的退出代码,并将其打印出来。 阅读详情

相关推荐

C++ Windows API 实现多线程

#include #include #include using namespace std; CRITICAL_SECTION cs;//定义一个全局的锁 CRITICAL_SECTION的实例,可以理解为锁定一个资源 int num = 0; DWORD WINAPI firstThread(__in LPVOID lpParameter){ EnterCriticalSection

yiyi0608的专栏 2364

Windows API编程之多线程

    在Windows的多线程编程中,创建线程的函数主要有CreateThread和_beginthread(及_beginthreadex)。 CreateThread 和 ExitThread     使用API函数CreateThread创建线程时,其中的线程函数原型:        DWORD WINAPI ThreadProc(LPVOID lpParameter)

技术收藏 8876

Windows API多线程编程实践

在现代软件开发中,多线程编程是提高应用程序性能的关键技术之一。Windows操作系统提供了丰富的API来创建和管理线程。本章将简要介绍Windows下线程创建的几种方法,为后续深入探讨线程机制打下基础。Windows API提供了几种基本的线程创建函数,最常用的包括和。是一个较为直接的函数,它允许开发者直接指定线程函数和初始堆栈大小。而则属于C运行时库,提供了额外的线程创建选项,如线程安全初始化等。让我们以为例,来看一下如何创建一个简单的线程:// 线程函数内容。

weixin_29607511的博客 704

运用API创建多线程

在Windows平台下创建多线程有两种方式,读者可以使用函数,或者使用函数均可,两者虽然都可以用于创建多线程环境,但还是存在一些差异的,首先函数它是Win32 API的一部分,而是C/C++运行库的一部分,在参数返回值类型方面,返回线程句柄,而返回线程ID,当然这两者在使用上并没有太大的差异,但为了代码更加通用笔者推荐使用后者,因为后者与平台无关性更容易实现跨平台需求。

不定时分享最优质的网络技术与教程,满满的干货。 347

多线程编程:Windows API与C++11的线程管理

本文深入探讨了在Windows环境下使用API进行线程等待的技巧,以及C++11标准如何简化线程同步与管理。通过对比Linux下的pthread_join函数和Windows的WaitForSingleObject和WaitForMultipleObjects函数,展示了不同操作系统在线程等待方面的差异。文章还详细介绍了C++11中std::thread类的join方法,并探讨了如何将C++类的实例方法用作线程函数,以及整型变量的原子操作问题。

weixin_42577243的博客 483

ARM Cortex-M系列授权解析:从研发到量产的免费与付费之路

本文深入解析了ARM Cortex-M系列内核从研发到量产过程中的授权模式。研发阶段可利用ARM DesignStart等免费资源进行原型验证,但产品商业化量产则需支付授权费与版税。文章对比了采购商用MCU与自研芯片的成本差异,并探讨了RISC-V作为免费替代方案在IoT领域的应用前景与挑战,为开发者提供了清晰的选型指南。

weixin_29292431的博客 494

Linux和Windows自带的API函数(主要在多线程中的函数使用)

前言 一、pandas是什么? 二、使用步骤 1.引入库 总结 提示:这里对文章进行总结:

记录一些平时工作或者学习中的瞬间 2328

【SigmaStar SSC335系列】空片用Flash_Tool烧写

简介 本文主要讲新拿到的PCBA,板上spi nand flash还是空的,如何在这种情况下烧录固件,这里讲解用官方Flash_Tool烧写的方式。 但只讲一些注意的地方和坑,其它的官方文档里说的比较清楚,不多说。 准备 Flash_Tool烧写软件 编译打包好烧写镜像 串口烧录小板 ----- 这个是个坑,在官方文档里并没有提及,刚开始用的平时调试的USB转串口,怎么都没反应,一度不知烧写软件不对还是硬件有问题,最后通过厂家技术支持才得知,除了专门的Flash_Tool外,还要专门的串口烧录器

老K 4699

多线程实例代码 - 面向过程语言

#include <iostream> #include <windows.h> using namespace std; DWORD WINAPI Fun(LPVOID lpParamter) { for (int i = 0; i < 10; i++) cout << "A Thread Fun Displa...

majunzhu的博客 355

《MySQL高级篇》十四、多版本并发控制

《MySQL高级篇》十四、多版本并发控制

LXYDSF的博客 3992

Kaggle赛题总结:Enefit - Predict Energy Behavior of Prosumers

竞赛旨在解决能源不平衡的问题,即预计使用的能源与实际使用或产生的能源不符。自发自用者是既消耗又产生能源的个体,他们在造成能源不平衡方面起到了重要作用。尽管他们只占所有能源消费者的一小部分,但他们不可预测的能源使用行为给能源公司带来了物流和财务问题。如果不加以解决,可能会导致运营成本增加、电网不稳定以及能源资源的低效利用。如果这个问题得到有效解决,将显著降低不平衡成本,提高电网的可靠性,并使自发自用者更高效和可持续地融入能源系统中。

猫敷雪 741

调用windows API实现多线程

调用windows API实现多线程 //最简单的创建多线程实例 #include &lt;stdio.h&gt; #include &lt;windows.h&gt; //子线程函数 DWORD WINAPI ThreadFun(LPVOID pM) { printf("子线程的线程ID号为:%d\n子线程输出Hello World\n", GetCurrentThreadId()); r...

shuayang1155的博客 1037

YOLO26科研升级:BiFPN双向特征金字塔,让多尺度特征融合精度再突破

在目录下,新建AddModules文件夹,将bifpn.py放入其中。

LXY_LOVE36的博客 559

windows api多线程

windows api多线程 原文地址:https://www.cnblogs.com/flowingwind/p/8452693.html 线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。 以上来自百度百科。多线程技术会让程序变得更加强大,是单线程永远无法实现的。例如,在命令行中,用户正在响应getchar函数,而我需要在用户...

weixin_30655219的博客 103

DeepLabv3+改进68:全网首发-添加DBlock模块 |高效且鲁棒的多任务低光图像修复神经网络

本文提出了一种高效鲁棒的多任务低光图像修复神经网络DarkIR,针对夜间或昏暗条件下图像存在的噪点、光线不足和模糊问题。不同于现有方法分别处理去模糊和低光增强任务,该模型采用新的注意力机制增强CNN感受野,在降低计算成本的同时,在LOL-Blur、LOLv2和Real-LOLBlur数据集上取得最优结果,并能良好泛化到真实夜间图像。

AIcurator的博客 325

手机VPN的连接方法分享

6、返回到VPN页面,可以看到刚刚新添加的VPN,点击开启VPN后面的开关。5、在打开的添加VPN的页面中输入VPN的信息后点击右上角的“保存”按钮。7、待VPN开关开启后,可以看到添加的VPN正在连接的提示信息了。2、在打开的小米手机设置页面中点击“更多连接方式”的菜单项。3、然后在打开的更多连接方式页面中点击VPN的菜单项。4、在打开的VPN设置页面中点击“添加VPN”的按钮。1、首先在手机屏幕左右的滑动,找到手机的设置图标。

惠惠软件 3万+

windows api 多线程

原文:http://blog.sina.com.cn/s/blog_5ff2c3320100flq1.html 线程是进程的一条执行路径,它包含独立的堆栈和CPU寄存器状态,每个线程共享所有的进程资源,包括打开的文件、信号标识及动态分配的内存等。一个 进程内 的所有线程使用同一个地址空间,而这些线程的执行由系统调度程序控制,调度程序决定哪个线程可执行以及什么时候执行线程。线程有优先级别,

labrary的专栏 1195

5.17华为OD机试真题 新系统 - 输出二叉树后序遍历结果 (Java/Py/C/C++/Js/Go)

5.17华为OD机试真题 新系统 - 输出二叉树后序遍历结果 (Java/Py/C/C++/Js/Go)

算法大师! 518

学懂C++(三十):高级教程——深入解析 C++ Windows API 的多线程支持

深入解析 C++ Windows API 的多线程支持

编程技术探索者,分享C/C++、C#、Java、数据库等开发经验,聚焦实战技巧与AI兴趣,助力编程爱好者成长。 2184

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

多线程(Windows API 以及 MFC支持的多线程)

转载:http://www.cppblog.com/amazon/archive/2008/11/27/67989.html 32位Windows环境下的Win32 API提供了多线程应用程序开发所需要的接口函数,而相应的MFC类库封装了多线程编程的类,用户在开发时可根据应用程序的需要和特点选择相应的工具。以下将概括归纳基于WIN32 API和MFC的多线程技术,以及线程通信的实现方法。 WI

白永辉的专栏 862

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

api windows 线程加锁_C/C++ Windows API——多线程加锁与临界区域

// MutexDemo.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include //createMutex#include //预先声明类class NormalArgs;//定义类的成员变量要加名空间typedef void (NormalArgs::*operatorFunc)();class NormalArgs {private:int cou...

weixin_29067143的博客 449

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Windows API 多线程-学习笔记(一)

Windows API 多线程-学习笔记(一) 一, winindows 下多线程的创建与撤销: windows 下多线程创建函数有两种,一种是调用系统API: CreateThread(), 另一种是调用C运行时函数库_beginthread()或_beginthreadex(),创建线程如果不再使用 //函数原型: //The thread object remains

jsm920的专栏 822

C语言中pthread或Windows API在多线程编程中的基本应用

现代操作系统通常以进程(process)作为CPU资源调度的最小单位,其实际上是线程的容器,而线程则是程序指令以及其资源的容器,从这样的角度,我们可以这样说:线程即是“程序”。我们为什么要使用多线程?原因是多种多样的,扯远一点,由于摩尔定律的失效(CPU单核性能在短期内无法取得决定性的进步),红蓝两家都在往CPU上堆核心,广大程序员无法享用单核红利。而着眼于手边,你可能会为了实现一个好看的读条界面而转向超线程,或者可能是为了在读取文件的同时输出日志,或者仅仅是想给自己的CPU来一次压力测试…......

qq_41757528的博客 2276

用标准 Windows API 创建多线程程序

用标准 Windows API 创建多线程程序 作者: aegeaner (1 篇文章) 日期: 十月 28, 2011 在 1:28 下午   1、 CreateThread()函数 用于创建一个新的线程。 01.HANDLE WINAPI CreateThread( 02. __in_opt LPSECURITY_ATTRIBUTES lpThreadAttr

autumn20080101的专栏 626

5.【Windows API程序设计】为什么使用多线程?

本文首先澄清多线程设计的目的并非单纯利用多核CPU,而是解决主线程无法处理的问题。通过Windows程序示例展示了线程的基础概念:可执行文件是静态的指令数据集合,进程是动态运行实例,线程是执行单元。当主线程进入死循环时(如示例中的Counter函数),会导致界面卡死,这正是需要创建子线程的场景。子线程共享进程资源但拥有独立执行流,通过时间片轮转实现"并发"。文章强调多线程的核心价值在于任务分解,而非硬件利用,单核处理器同样需要多线程来避免主线程阻塞。

2503_92964515的博客 1011

Windows API 封装多线程编程

将Windows 多线程API封装成一个类XThread,//XThread.h#pragma once #ifdef XPLATFORM_EXPORTS #define XPLATFORM_API __declspec(dllexport) #else #define XPLATFORM_API __declspec(dllimport) #endif class XPLATFORM_API ...

qq_26272885的博客 353
上一篇: C/C++ 、VS、linux 内存泄露检测
下一篇: windows api 多线程
labrary
博客等级 码龄15年 8粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值