• 多线程的些许理解(平台x86,具体考虑linux,windows)


                      多线程的些许理解

    一.体系架构

    1.原子操作 

    1) 定义

     不可中断的一个或者一系列操作,也就是不会被线程调度机制打断的操作,在运行期间不会有任何的上下文切换(context switch).

    2) 我们为什么关注原子操作(what)

     在多线程操作的时候,确定某个操作非原子操作,要用消耗性能的昂贵的锁去保护。

    3)单核CPU、多核CPU

          在单核CPU中,能够在一个指令中完成的操作都可以看作为原子操作,因为中断只发生在指令间。

          在多核CPU中,软件级别的原子操作依赖于硬件支持的,在X86体系中,CPU提供了HLOCK pin引 线,允许CPU在执行某个指令(仅仅是一个指令)时拉低HLOCK pin引线的电平,直到这个这个指令执行完毕才放开。拉低电平导致锁住总线,如此在同一总线的CPU就暂时无法通过总线访问内存了,这样就保证了多核处理器的原子操作。(在那段时间,我猜测,处理器,在想为啥内存访问被禁止,什么鬼,交 通管制,又是哪个大领导来视察)

     4)如何定义操作原子操作

            对于非long和double基本数据类型的“简单操作”都可以看作原子操作。for example:赋值和返回。在大多数系统中long和double都占据8个字节,操作系统或者JVM(java虚拟机)很可能会将写入和读取操作分离成两个独立的操作来执行,这就产生一个读取和写入过程中的上下文切换,从而导致多线程看到不正确的情况。

            自增,自减非原子操作,一共三步(两次内存访问,一次寄存器修改)

            比如:x++;(没有招,兄弟牺牲点性能吧)

    mov        eax,dword ptr [x]
    add         eax,1
    mov        dword ptr  [x],eax

      

    二、操作系统之上的实现

        讲点没有用,有大咖测试发现,在linux上进程和线程的效率差不多,window上进程和线程效率差距很大。

    1.window上多线程同步和互斥操作

            分别有四种方式:临界区(CriticalSection)、互斥对象(Mutex)、信号量(Semaphore)、事件对象(Event)。

    1)临界区:

       使用函数:

    CRITICAL_SECTION CriticalSection;
    InitializeCriticalSection(&CriticalSection);
    EnterCriticalSection(&CriticalSection);
    LeaveCriticalSection(&CriticalSection);
    DeleteCriticalSection(&CriticalSection);
    

     write an example:

    #include <string>
    #include <iostream>
    #include < process.h>
    #include <windows.h>
    using namespace std;
    
    CRITICAL_SECTION g_cs;
    
    unsigned __stdcall threadFun(void *param)
    {
         EnterCriticalSection(&g_cs);
         cout<<*(string*)(param)<<endl;
         LeaveCriticalSection(&g_cs);
         return 1;        
    }
    
    int main()
    {
             InitializeCriticalSection(&g_cs);
              
             HANDLE  hth1, hth2, hth3;
             string s1 = "first", s2 = "second", s3= "third";
             
             hth1 = (HANDLE)_beginthreadex(NULL, 0, threadFun, &s1, 0, NULL);
             hth2 = (HNADLE)_beginthreadex(NULL, 0, threadFun, &s2, 0, NULL);
             hth3 = (HNADLE)_beginthreadex(NULL, 0, threadFun, &s3, 0, NULL);
    
             WaitForSingleObject(hth1, INFINITE);
             WaitForSingleObject(hth2, INFINITE);
             WaitForSingleObject(hth3, INFINITE);
    
            CloseHandle(hth1);
            CloseHandle(hth2);
            CloseHandle(hth3);
        
            DeleteCriticalSection(&g_cs); 
            return  0; 
    }
    

    2) 互斥对象(Mutex)

      引入了对象互斥对象的概念,来保证共享数据操作的完整性,每个对象对应于一个可称为互斥锁的标记,用这个标记用来保证在任一时刻,只要有一个线程访问该对象,操作接口:

    CreateMutex
    OpenMutex
    ReleaseMutex
    

    write an example:

    #include<string>
    #include<iostream>
    #include<process.h>
    #include<windows.h>
    using namespace std;
    
    HANDLE hmu;
    
    unsined __stdcall threadFun(void *param)
    {
          WaitForSingleObject(hmu, INFINITE);
          cout<<*(string*)(param)<<endl;
          ReleaseMutex(hmu);
          return 1;
    }
    
    int main()
    {
            hmu = CreateMutex(NULL, FALSE, NULL);
            HANDLE hth1, hth2, hth3;
            string s1 = "first", s2 = "second", s3 = "third"; 
    
            hth1 = (HANDLE)_beginthreadex(NULL, 0, threadFun, &s1, 0, NULL);
            hth2 = (HANDLE)_beginthreadex(NULL, 0, threadFun, &s2, 0, NULL);
            hth3 = (HANDLE)_beginthreadex(NULL, 0, threadFun, &s3, 0, NULL);
    
            WaitForSingleObjec(hth1, INFINITE);
            WaitForSingleObjec(hth2, INFINITE);
            WaitForSingleObject(hth3, INFINITE);
     
            CloseHandle(hth1);
            CloseHandle(hth2);
            CloseHandle(hth3);
    
            CloseHandle(hmu); 
             return 0; }

    3)信号量(Semaphore) 

          信号量,别称信号灯。负责协调各个线程,保证正确合理的使用公共资源。

         window环境接口:

    CreateSemaphore
    OpenSemaphore
    ReleaseSemaphore
    

     write an example:

    #include <string>
    #include <iostream>
    #include <process.h>
    #include <windows.h>
    
    using namespace std;
    
    HANDLE hsem1, hsem2, hsem3;
    
    usigned __stdcall threadFunA(void *)
    {
           for(int i = 0; i < 10; i++)
           {
                 WaitForSingleObject(hsem1, INFINITE);
                  cout<<"A";
                  ReleaseSemaphore(hsem2, 1, NULL);
            }  
            return 1;
    }
    
    unsigned __stdcall threadFunB(void*)
    {
             for(int i = 0; i < 10; i++)
             {
                WaitForSingleObject(hsem2, INFINITE);
                cout<<"B";
                ReleaseSemaphore(hsem2, 1, NULL);
              }  
              return 1;
    }
    
    unsigned __stdcall threadFunC(void*)
    {
           for(inti =0; i < 10; i++)
           {
               WaitForSingleObject(hsem3, INFINITE);
               cout<<"C";
               ReleaseSemphore(hsem1, 1, NULL);
            }    
            return 1;
    }
    
    
    int main()
    {
                  hsem1 = CreateSemaphore(NULL, 1, 1, NULL);
                  hsem2 = CreateSemaphore(NULL, 0, 1, NULL);
                  hsem3 = CreateSemaphore(NULL, 0, 1, NULL);
    
                   HANDLE hth1, hth2, hth3;
    
                   hth1 = (HANDLE)_beginthreadex(NULL, 0, threadFunA, NULL, 0, NULL);
                  hth2  = (HANDLE)_beginthreadex(NULL, 0, threadFunB, NULL, 0, NULL);
                   hth3 = (HANDLE)_beginthreadex(NULL, o, threadFunC, NULL, 0, NULl);
    
                    WaitForSingleObject(hth1, INFINITE);
                    WaitForSingleObject(hth2, INFINITE);
                     WaitForSingleObject(hth3, INFINITE);
    
                    CloseHandle(hth1);
                    CloseHandle(hth2);
                    CloseHandle(hth3);
                    CloseHandle(hsem1);
                    CloseHandle(hsem2);
                    CloseHandle(hsem3);
                    return 0;
    }
     
    

    4) 事件对象(Event)

     windows事件操作

    CreateEvent
    OpenEvent
    PulseEvent
    ResetEvent
    SetEvent
    

    主线程一般可以这样写:

    CreateEvent(/*...*/);    // 创建事件对象
    SetEvent(/*...*/);       // 设置信号
    WaitForMultiObjects(hThread, /*...*/);    // 等待线程结束
    CloseHandle(/*...*/);    // 关闭线程句柄
    

    而被启动的线程一般要等待某个事件再进行操作:

    while(1){
        WaitForSingleObject(/*...*/);    // 等待事件
        /*...*/
    }
    

    总结:

           1. 使用频率,信号量 > 互斥对象 > 临界区 > 事件对象 

           2. windows编程中有两种创建线程的方法,一种为CreateThread(),另一种为_beginthreadex(),当如果代码使用标准C运行库,建议使用后者。 (window API的好)

    2.linux  c 多线程编程

           无非也是锁机制,条件变量,读写锁,在linux编程中多线程和多进程差不多,无非API改改名,不做太多探讨。

           write  simple an example:

               

    #include"../apue.h"
    int pos=0;
    char *list[10]={"person1","person2","person3","person4","person5",
    		"person6","person7","person8","person9","person10"};
    
    pthread_mutex_t mutex; 
    void *func(void *p)
    {
    	int a = *(int*)p;	
    	for(;;)
    	{
    		pthread_mutex_lock(&mutex);	
    		if(pos>=10)
    		{
    			break;
    		}
    		printf("%d号咨询美女为%s服务
    ",a,list[pos]);
    		pos++;	
    		pthread_mutex_unlock(&mutex);
    		sleep(8);//模拟服务时间
    	}
    	pthread_mutex_unlock(&mutex);
    }
    int main()
    {
    	int i;
    	int a=1,b=2,c=3;
    	pthread_t id1,id2,id3;
    	pthread_mutex_init(&mutex,NULL);
    	pthread_create(&id1,NULL,func,&a);
    	pthread_create(&id2,NULL,func,&b);
    	pthread_create(&id3,NULL,func,&c);
    
    	pthread_join(id1,NULL);
    	pthread_join(id2,NULL);
    	pthread_join(id3,NULL);
    	while(1);
    }
    

      参考:网上的博客 (集百家之所长,补自己之所短)

                      《UNIX环境高级编程》这本书看完了,验证一遍,linux基本操作都应该没啥问题。

                   

    The future's not set,there is no fate but what we make for ourselves.
  • 相关阅读:
    简单的python购物车
    MS17-010漏洞复现
    记一次简单的sql注入
    利用钟馗之眼对摄像头入侵
    分流抢票软件浅谈
    一次简单的路由器渗透
    运动目标检测中基于HSV空间的阴影去除算法
    RGB颜色空间、HSV颜色空间的理解
    #ifdef __cplusplus extern "C" { #endif 含义
    Opencv 视频保存为图像
  • 原文地址:https://www.cnblogs.com/wang1994/p/10954510.html
Copyright © 2020-2023  润新知