进程和线程

1.进程与线程
程序:
    当代码写完后,编译会生成一个.exe文件,存储在硬盘中;这就是程序;
 
内存镜像:
    exe文件双击执行时,会加载到内存中;
    exe文件在内存中的状态和在文件中的状态不同;
    内存中的状态是pe结构拉伸后的状态;
    pe结构拉升后的状态称为内存镜像;
    pe文件的内存镜像并不一定可以运行,只是具备了运行的条件;
    如果内存镜像文件要能够运行,需要创建一个线程,并将eip交给线程;此时内存镜像就可以运行也就变成了进程;
 
总之在硬盘中保存的exe文件就是程序;
跑起来的程序就是进程;
一个进程中至少会有一个线程;
 
打开任务管理器:
可以看到进程idea64.exe,有47个线程,pid是10432等等;
 
2.多线程程序
每一个进程都有一个独立的4gb虚拟空间;
进程就是用来描述这4gb空间中放什么;
线程就是进程中有几个同时执行的程序;
 
创建新线程的API函数:只管创建线程不管线程的功能
HANDLE CreateThread(                
  LPSECURITY_ATTRIBUTES lpThreadAttributes, // 安全属性 通常为NULL                
  SIZE_T dwStackSize,                       // 参数用于设定线程可以将多少地址空间用于它自己的堆栈               
                                            // 每个线程拥有它自己的堆栈;设0系统会自动给线程分配空间
  LPTHREAD_START_ROUTINE lpStartAddress,    // 参数用于指明想要新线程执行的线程函数的地址;函数地址是一个全局变量,函数名就是该全局变量                
  LPVOID lpParameter,                       // 线程函数的参数                
                                            // 在线程启动执行时将该参数传递给线程函数
                                            // 既可以是数字,也可以是指向包含其他信息的一个数据结构的指针
  DWORD dwCreationFlags,                    // 0 创建完毕立即调度  CREATE_SUSPENDED创建后挂起                
  LPDWORD lpThreadId                        // 线程ID; out参数,线程是内核创建的创建完成后会生成一个线程id,用来唯一标识该线程                 
);                
                                            // 返回值:线程句柄,3环程序想要操作该线程需要获取线程句柄
线程句柄与线程ID:                
    线程是由Windows内核负责创建与管理的,句柄相当于一个令牌,有了这个令牌就可以使用线程对象.                
    线程ID是身份证,唯一的,系统进行线程调度的时候要使用的.                
 
实例:
#include<stdio.h>
#include<windows.h>
 
//线程函数
DWORD WINAPI ThreadProc(                
             LPVOID lpParameter   // 给线程传递参数       
             ){
    for(int i=0;i<100;i++){
        Sleep(1000);
        printf("-----------%d\n", (int)lpParameter);
    }
    return 0;
}
 
//创建线程
void fun(){
    int x = 2;    //用来传到线程中的参数
    //创建一个新的线程                
    HANDLE hThread = ::CreateThread(NULL, 0, ThreadProc, (void*)x, 0, NULL);  //不能直接传递x的地址,因为线程切换时堆栈会销毁,存在堆栈中的临时变量的地址将不准确          
    //如果不在其他的地方引用它 关闭句柄                
    ::CloseHandle(hThread);
}
 
//主函数
void main(){
    fun();
    for(int i=0; i<100;i++){
        Sleep(1000);
        printf(">>>>>>>>>>>>\n");
    }
    
}          
结果:
可以看到有两种输出;
说明主线程和创建的新线程在交替运行;
也就是说进程的4gb空间可以有1个线程干活,也可以有多个线程干活;
 
向线程函数传递变量的两种方式:            
    全局变量            
    线程参数            
 
3.利用多线程实现的倒计时程序
目标:
    点击开始后,第一个文本框的值从1000每隔1秒种减1 直到0
    第二个文本框从0每隔1秒钟加1 直到1000
 
用到的API函数:
//文本框赋值:        
SetWindowText(句柄,数据缓存区);        
        
//文本框取值:        
GetWindowText(句柄,数据缓冲区,长度);        
        
//数字转字符:        
sprintf(数据缓冲区,"%d",数字);        
        
//字符转数字:        
sscanf( szBuffer, "%d", &dwTimer );        
        
//获取子窗口:        
GetDlgItem(hDlg,IDC_EDIT_TIMER);      
  
代码:
#include<windows.h>
#include<stdio.h>
#include "resource.h"
 
HWND sub;
HWND plus;
 
//倒计时;需要单独的线程来执行该功能,因为主线程需要用来处理消息循环不能被占用;
DWORD WINAPI doSub(LPVOID lpParameter){
    //MessageBox(NULL,TEXT("go"),TEXT("GO"),MB_OK);
    //获取文本框内容
    TCHAR szBuffer[10];
    memset(szBuffer, 0, 10);
    GetWindowText(sub, szBuffer, 10);
    //字符转数字
    DWORD time;
    sscanf(szBuffer, "%d", &time);
    //计算并写回文本
    while(time > 0){
        memset(szBuffer, 0, 10);
        Sleep(1000);
        sprintf(szBuffer,"%d", --time);
        SetWindowText(sub,szBuffer);
    }
    return 0;
}
 
//顺计时
DWORD WINAPI doPlus(LPVOID lpParameter){
    //获取文本框内容
    TCHAR szBuffer[10];
    memset(szBuffer, 0, 10);
    GetWindowText(plus, szBuffer, 10);
    //字符转数字
    DWORD time;
    sscanf(szBuffer, "%d", &time);
    //计算并写回文本
    while(time < 1000){
        memset(szBuffer, 0, 10);
        Sleep(1000);
        sprintf(szBuffer,"%d", ++time);
        SetWindowText(plus,szBuffer);
    }
    return 0;
}
 
//回调函数
BOOL CALLBACK DialogProc(                                    
                         HWND hwndDlg,  // handle to dialog box            
                         UINT uMsg,     // message            
                         WPARAM wParam, // first message parameter            
                         LPARAM lParam  // second message parameter            
                         )            
{    
    switch(uMsg)                                
    {    
    case WM_INITDIALOG :
        {
            //初始化文本框
            sub = GetDlgItem(hwndDlg,IDC_SUB);
            SetWindowText(sub,TEXT("1000"));
            plus = GetDlgItem(hwndDlg, IDC_PLUS);
            SetWindowText(plus,TEXT("0"));
        }
        return TRUE;     
                                    
    case  WM_COMMAND :                                
        switch (LOWORD (wParam))                            
        {
        case IDC_BTN_GO:  
            HANDLE hThread = ::CreateThread(NULL, 0, doSub, NULL, 0, NULL);        
            //如果不在其他的地方引用它 关闭句柄                
            ::CloseHandle(hThread);
 
            HANDLE hThread2 = ::CreateThread(NULL, 0, doPlus, NULL, 0, NULL);                     
            ::CloseHandle(hThread2);
            return TRUE;                       
        }                            
        break ;   
        
    case WM_CLOSE:
        EndDialog(hwndDlg, 0);
        return TRUE;
    }    
                                    
    return FALSE ;                                
}    
 
int CALLBACK WinMain(
                     HINSTANCE hInstance,
                     HINSTANCE hPrevHinstance,
                     LPSTR lpCmdLine,
                     int nCmdShow
                     ){
    //创建窗口
    DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogProc);
    return 0;
}
 结果:
   
 
 
 
posted @ 2019-12-25 13:55  L丶银甲闪闪  阅读(299)  评论(0编辑  收藏  举报