• 多线程编程基础


    线程:进程上下文中执行的代码序列,又名轻量级进程。

    在支持多线程的系统中,进程成为资源分配和保护的实体,线程是被调度执行的基本单元。进程是拥有资源的最小单位。

    线程的分类

    1)核心态线程(内核级线程):所有管理操作都是有操作系统内核完成的

    2)用户态线程(用户级线程):一般我们操作的线程都是用户态线程。由用户级实现的线程 库来支持

    用户级线程特征

    1)用户级线程的创建和管理等操作无需内核参与,操作更快

    2)并行性不高,一个线程被系统阻塞后,整个进程被阻塞

     

    内核级线程特征

    1)并行性高:多个线程可被提供是调度,充分利用多核处理器

    2)创建和管理代价高

     

    多线程(同一时刻可运行多个线程)优点

    1)创建一个线程比创建一个进程的代价小

    2)线程的切换比进程间的切换代价小

    3)充分利用多核处理器

    4)数据共享:使得线程之间的通信比进程间的通信更高效

    5)快速响应特性:在系统繁忙的情况下,进程通过独立的线程及时响应用户的输入

     

    Windows显示主要使用Win32 API实现

    windows常用线程操作函数:创建线程函数、管理线程函数、终止线程函数、线程同步函数

    线程必须从指定的函数开始,也就是这个函数其实就是线程的入口函数

    DWORD WINAPI ThreadFunc(LPVOID IpvThreadParm);

    线程创建函数是Windows API标准函数

    HANDLE CreateThread(
    
    LPSECURITY_ATTRIBUTES  IpThreadAttributes //安全属性,设为null就可以
    
    SIZE_T                 dwStackSize,     //内存的大小,栈的大小  可以为0
    
    LPTHREAD_START_ROUTINE IpStartAddress,  //函数的指针,指向线程函数
    
    LPVOID                 IpParameter,     //传递的参数,可以为空
    
    DWORD                  dwCreationFlags,  //创建标志,只能为0或者CREATE_SUSPENDED.0表示创建之后就会执行,CREATE_SUSPENDED表示创建之后处于挂起状态(观其计数器为1)
    
    LPDWORD                IpThreadId        //线程的ID好,可以不写
    
    );//返回值是句柄
    View Code

    _beginthread函数是vc里面创建线程的函数。里面的实质还是API的创建函数

    hThread=_beginthread(
    
    void(*strat_address)(void *),//线程函数的指针
    
    unsigned stack_size,  //栈的大小
    
    void *arglist //参数列表
    
    );
    View Code

     示例

    #include<stdio.h>
    #include<windows.h>
    #include<process.h>
    #include<iostream>
    #include<fstream>
    using namespace std;
    
    void ThreadFunc1(PVOID param){
        while(1){
            Sleep(1000);
            cout<<"This is ThreadFunc1"<<endl;
        }
    }
    
    void ThreadFunc2(PVOID param){
        while(1){
            Sleep(1000);
            cout<<"This is ThreadFunc2"<<endl;
        }
    }
    
    int main(){
        int i=0;
        _beginthread(ThreadFunc1,0,NULL);
        _beginthread(ThreadFunc2,0,NULL);
        
        Sleep(3000);
        cout<<"end"<<endl;
        cin>>i;//这句话是为了让主程序停止在这里
        
        return 0; 
    }
    View Code

    线程是一个函数的表示方法

    在时间片轮转中,主线程有优先权(主线程结束,子线程自动结束),跟编译器有关

    main是主线程,另外两个是子线程,主线程走自己的,子线程也走自己的,三个线程同时执行

    主线程死掉,子线程自动结束,三个线程是独立的。

    这三个线程加上其余计算机上的线程一起在windows中进行调度,所以即便是先创建线程1,再创建线程2,但是也有可能先执行线程2再执行线程1.所以多次运行结果会不同

    在分配给CPU区域的时候,该CPU可能将其挂起等等操作。队列也不同。最后结果可能就千差万别。需要使用更多的函数,使得线程满足我们自己的需求

    进程中的每个线程都有挂起计数器。当挂起计数器为0时,线程被执行;当挂起计数器大于0时,调度器不去调取该线程

    挂起线程函数  挂起计数器加1

    DWORD SuspendThread(
    
    HANDLE hThread;//线程函数的句柄
    
    );
    View Code

    解挂函数   挂起计数器减1

    DWORD ResumeThread(
    
    HANDLE hThread  //线程函数的句柄
    
    );
    View Code

    线程终结函数

    线程内部终结线程

    VOID ExitThread(DWORD dwExitCode);//参数:退出码(线程以什么方式退出)

    在线程外终结线程

    BOOL TerminateThread(//返回值bool表示执行成功还是失败
    
    HANDLE hThread,  //被终止的线程的函数名(句柄)
    
    DWORD dwExitCode //退出码
    
    );
    View Code

    示例

    #include<stdio.h>
    #include<windows.h>
    #include<iostream>
    using namespace std;
    
    DWORD WINAPI FunOne(LPVOID param){
        while(true){
            Sleep(1000);
            cout<<"hello!";
        }
        return 0;
    }
    
    DWORD WINAPI FunTwo(LPVOID param){
        while(true){
            Sleep(1000);
            cout<<"world!";
        }
        return 0;
    }
    
    int main(){
        int input=0;
        HANDLE hand1=CreateThread(NULL,0,FunOne,(void *)&input,CREATE_SUSPENDED,NULL); 
        HANDLE hand2=CreateThread(NULL,0,FunTwo,(void *)&input,CREATE_SUSPENDED,NULL); 
        
        while(true){
            cin>>input;
            if(input==1){
                ResumeThread(hand1);
                ResumeThread(hand2);
            }
            else {
                SuspendThread(hand1);
                SuspendThread(hand2); 
            }
        }
        
        TerminateThread(hand1,1);
        TerminateThread(hand2,1);
        return 0;
    }
    View Code


    作者:孙建钊
    出处:http://www.cnblogs.com/sunjianzhao/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    Oracle Day2
    Orcale Day1
    JavaSE 单例模式
    C#Windows 服务的安装说明
    Json转Hashtable的转换
    将汉字转为拼音
    游标 的使用
    C#后台画图保存为ipg/png的文件
    T-sql 查询
    EF简单的添加修改删除基本语法
  • 原文地址:https://www.cnblogs.com/sunjianzhao/p/14470016.html
Copyright © 2020-2023  润新知