精华内容
下载资源
问答
  • 动态链接的全局变量与多线程
    千次阅读
    2018-09-30 16:48:16

    最近对多线程调用时,动态链接库的全局变量有了以下几点认识。

    1、动态链接库被同一进程的多个线程加载时,全局变量的值是进程有效。

       例如:动态链接库C.dll有一个全局变量 int g_iCount=0(初始值)。某一函数Method_D被调用一次,则g_iCount++。

                  当某一进程加载C.dll后,线程A、B先后调用Method_D后,线程A获得的C.g_iCount=1,但线程B获得的C.g_iCount则是2。

        这是因为线程B调用Method_D前,g_iCount已经被线程A更改。

     

    2、虽然说动态链接库的全局变量是进程级的,但并不是说 同一进程里,不同模块定义同名全局变量就可以互相传递数值。

         这跟我们的函数一样,即使在同一进程空间里,定义成相同名字跟结构,只要没有做导出,外部模块还是不能调用的。

         所以,如果想在同一进程的不同线程间共享某一数据,也可以在全局变量定义时,使用_declspec(dllexport) 将其导出,

          在调用处使用GetProcAddress()取得其在进程空间的地址来使用。

    更多相关内容
  • 好用的c++多线程软件 Pthread visual studio可用,mfc可用
  • C/C++:多线程使用dlopen、dlsym、dlclose装载动态库

    C/C++:多线程下使用dlopen、dlsym、dlclose装载动态库

    当在多线程下dlopen同一个动态库,使用的会是同一个动态库实例还是不同的动态库实例呢?

    count.h

    #ifndef _COUNT_H
    #define _COUNT_H
    
    #include <pthread.h>
    
    int count;
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    
    
    int get();
    void inc();
    
    #endif
    

    count.c

    #include "count.h"
    
    int get()
    {
        return count;
    }
    
    void inc()
    {
        pthread_mutex_lock(&mutex);
        count++;
        pthread_mutex_unlock(&mutex);
    }
    
    编译生成libcount.so

    main.c

    #include <stdio.h>
    #include <dlfcn.h>
    #include <pthread.h>
    
    #define NUM 1000 
    #define LIBPATH "/home/test1280/libcount.so"
    
    static const char *threadA = "Thread-A";
    static const char *threadB = "Thread-B";
    
    void *ThreadRun(void *arg)
    {
        usleep(500*1000);
        printf("Start:%s\n", (char *)arg);
    
        void *handler = dlopen(LIBPATH, RTLD_LAZY);
        if (handler == NULL)
        {
            printf("ERROR:%s:dlopen\n", dlerror());
        }
    
        void (*inc)() = (void (*)())dlsym(handler, "inc");
        if (inc == NULL)
        {
            printf("ERROR:%s:dlsym\n", dlerror());
        }
    
        int i = 0;
        for (; i < NUM; i++)
        {
            inc();
        }
    
        int (*get)() = (int (*)())dlsym(handler, "get");
        if (get == NULL)
        {
            printf("ERROR:%s:dlsym\n", dlerror());
        }
        printf("INFO:%s:get() return %d\n", (char *)arg, get());
    
        dlclose(handler);
    }
    
    int main()
    {
        pthread_t tid1;
        pthread_t tid2;
    
        pthread_create(&tid1, NULL, ThreadRun, (void *)threadA);
        printf("create Thread-A OK!!!\n");
        pthread_create(&tid2, NULL, ThreadRun, (void *)threadB);
        printf("create Thread-B OK!!!\n");
    
        while (1);
    
        return 0;
    }
    
    [test1280@localhost ~]$ gcc -o main main.c -ldl -lpthread
    [test1280@localhost ~]$ ./main
    create Thread-A OK!!!
    create Thread-B OK!!!
    Start:Thread-A
    INFO:Thread-A:get() return 1000
    Start:Thread-B
    INFO:Thread-B:get() return 1000
    ^C
    

    这么看来同一进程实体不同线程dlopen相同的库会得到不同的实例?

    一个动态库会在同一进程同一时刻同时被加载多次?

    当然不对啦!

    那按照我们期待的,希望输出的最后的值应该是2000,那为何是1000呢?

    原因:

    线程A或者线程B跑的太快了,在一个时间片内就已经做完:
    1.装载动态库到当前进程;
    2.获得函数地址;
    3.调用inc指定次数;
    4.输出get返回值;
    5.dlclose卸载动态库;

    注意:

    dlclose时,此时此刻可能仅仅只有一个线程在跑着,另一个线程还没有dlopen那个动态库,此时只有一个线程持有libcount.so的句柄,然后做完所有操作,dlclose,发现对库的引用减少至0,就将libcount.so从当前进程卸载;

    然后呢,就是另一个线程在跑,再打开dlopen同一个动态库,然后里面的全局变量(库内全局)静态初始化为0,然后inc,然后…

    结果很明显:是由于某个线程跑的太快,导致另一个线程还没有执行dlopen时,前一个进程已经做完所有活了(包括卸载libcount.so库),当另一个线程执行dlopen时,完全不知道这个库曾经被加载到当前进程…于是库中全局变量又静态初始化…

    这样的时序看来,输出两个1000合情合理.

    如何验证我们刚刚说的时序呢?

    修改下main.c:

    #include <stdio.h>
    #include <dlfcn.h>
    #include <pthread.h>
    
    #define NUM 1000 
    #define LIBPATH "/home/test1280/libcount.so"
    
    static const char *threadA = "Thread-A";
    static const char *threadB = "Thread-B";
    
    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    
    void *ThreadRun(void *arg)
    {
        usleep(500*1000);
        printf("Start:%s\n", (char *)arg);
    
        void *handler = dlopen(LIBPATH, RTLD_LAZY);
        if (handler == NULL)
        {
            printf("ERROR:%s:dlopen\n", dlerror());
        }
    
        void (*inc)() = (void (*)())dlsym(handler, "inc");
        if (inc == NULL)
        {
            printf("ERROR:%s:dlsym\n", dlerror());
        }
    
        int i = 0;
        for (; i < NUM; i++)
        {
            inc();
        }
    
        int (*get)() = (int (*)())dlsym(handler, "get");
        if (get == NULL)
        {
            printf("ERROR:%s:dlsym\n", dlerror());
        }
        printf("INFO:%s:get() return %d\n", (char *)arg, get());
    
        pthread_mutex_lock(&mutex);
        dlclose(handler);
        printf("INFO:lib unload && %s END...\n", (char *)arg);
        pthread_mutex_unlock(&mutex);
    }
    
    int main()
    {
        pthread_t tid1;
        pthread_t tid2;
    
        pthread_create(&tid1, NULL, ThreadRun, (void *)threadA);
        printf("create Thread-A OK!!!\n");
        pthread_create(&tid2, NULL, ThreadRun, (void *)threadB);
        printf("create Thread-B OK!!!\n");
    
        while (1);
    
        return 0;
    }
    
    [test1280@localhost ~]$ gcc -o main main.c -ldl -lpthread
    [test1280@localhost ~]$ ./main
    create Thread-A OK!!!
    create Thread-B OK!!!
    Start:Thread-A
    INFO:Thread-A:get() return 1000
    INFO:lib unload && Thread-A END...
    Start:Thread-B
    INFO:Thread-B:get() return 1000
    INFO:lib unload && Thread-B END...
    ^C
    

    另外,我想看看两个线程对同一个库实例进行操作是什么效果…?

    我们只要让两个线程同时(同一时刻)对一个库保持打开状态即可(不dlclose):

    将ThreadRun中最后的dlclose删除,如下main.c所示:

    void *ThreadRun(void *arg)
    {
        usleep(500*1000);
        printf("Start:%s\n", (char *)arg);
    
        void *handler = dlopen(LIBPATH, RTLD_LAZY);
        if (handler == NULL)
        {
            printf("ERROR:%s:dlopen\n", dlerror());
        }
    
        void (*inc)() = (void (*)())dlsym(handler, "inc");
        if (inc == NULL)
        {
            printf("ERROR:%s:dlsym\n", dlerror());
        }
    
        int i = 0;
        for (; i < NUM; i++)
        {
            inc();
        }
    
        int (*get)() = (int (*)())dlsym(handler, "get");
        if (get == NULL)
        {
            printf("ERROR:%s:dlsym\n", dlerror());
        }
        printf("INFO:%s:get() return %d\n", (char *)arg, get());
    
        //delete...
        //dlclose(handler);
    }
    
    [test1280@localhost ~]$ ./main
    create Thread-A OK!!!
    create Thread-B OK!!!
    Start:Thread-A
    INFO:Thread-A:get() return 1000
    Start:Thread-B
    INFO:Thread-B:get() return 2000
    ^C
    

    当然,这个示例并不好,有dlopen,就应该有配套的dlclose,虽然如此,但是可以很好地验证我们的设想.

    结论:

    同一进程同一时刻,不同线程通过dlopen打开相同的动态库,只是把一份动态库装载到当前进程,进程中仅仅有一个动态库实例,动态库中全局变量对各个线程来说是“同一份”.

    同一进程不同时刻,不同线程虽然dlopen了,但是可能由于时序问题以及dlclose卸载动态库,存在多次加载动态库的情况,那么也就是从进程的整体生命周期来看是不同的库实例了,库中的全局变量对于不同的线程,在不同的时间段来说是“不相同的”.

    同一时刻,一个进程内仅仅有同一个动态库实例哦.

    展开全文
  • 【c++】求大神回复,我的动态库被别人使用多线程调用,我单线程调用了一个别人写的动态库,我调的这个库需不需要支持可重入,要不要加锁保护?我调的库,我把它当一个函数使用,它里面也挺复杂的,好多全局变量。
  • Windows c++在类中使用多线程

    千次阅读 2019-08-17 15:13:22
    在类中使用多线程的简单步骤及例子: 1,在类中将线程函数写成静态成员函数(也可以将线程函数做成全局函数)。 2,参数为(LPVOID pParam)用来传入类 对象指针this,也可以传入其他数据结构。 3,进入调用线程函数...

    由于当前开发环境为VS2010,暂时不能使用c++11  std 中的thread类,这里只能使用WINapi   CreateThread来创建线程。

    一.在类中使用多线程的简单步骤及例子:

    1,在类中将线程函数写成静态成员函数(也可以将线程函数做成全局函数)。

    2,参数为 (LPVOID pParam)用来传入类 对象指针this,也可以传入其他数据结构。

    3,进入调用线程函数的函数时,首先将 类名 *this = (类名*)this;  转化为对象指针。

    4,之后用this调用类成员变量和方法就行了。

    5,然后使用CreateThread开启线程即可。

    方法第三个参数传入该静态函数,CreateThread第四个参数传入对象指针this,最后一个参数可以输出所创建的线程的ID,其他参数可以参考下面的函数介绍

    简单示例:

    //类头文件  my.h
    
    #include<Windows.h>
    
    class myclass
    {
        public:
            static DWORD WINAPI ThreadFun(LPVOID pParam);   线程函数声明
    
        public:
            void MyTestFun();
            int one;
        
    }
    
    
    
    //类实现文件  my.cpp
    #include "stdafx.h"
    #include "my.h"
    
    DWORD WINAPI myclass::ThreadFun(LPVOID pParam)  //线程函数实现
    {
       //在线程中要做的事情
       myclass *pObj = (myclass *)pParam;   //传入的参数转化为类对象指针
    
       int two;
    
       two=pObj->one;
       return 0;
    }
    
    void myclass::MyTestFun()
    {
       HANDLE hThread;   //线程句柄
       DWORD  threadId;  //线程ID
    
       hThread = CreateThread(NULL, 0, ThreadFun, this, 0,&threadId); // 创建线程,this就是本类的对象指针
    
    }
    
    
    
    
    
    

    二.CreateThread 函数介绍:

    创建一个在调用进程的虚拟地址空间内执行的线程。

    要创建在另一个进程的虚拟地址空间中运行的线程,请使用 CreateRemoteThread函数。

    语法

    HANDLE CreateThread(
      LPSECURITY_ATTRIBUTES   lpThreadAttributes,
      SIZE_T                  dwStackSize,
      LPTHREAD_START_ROUTINE  lpStartAddress,
      __drv_aliasesMem LPVOID lpParameter,
      DWORD                   dwCreationFlags,
      LPDWORD                 lpThreadId
    );



    参数
    lpThreadAttributes
    指向SECURITY_ATTRIBUTES 结构的指针,该结构确定子进程是否可以继承返回的句柄。如果 lpThreadAttributes为NULL,则无法继承句柄。

    结构的lpSecurityDescriptor成员为新线程指定安全描述符。如果lpThreadAttributes为NULL,则线程获取默认安全描述符。线程的默认安全描述符中的ACL来自创建者的主要标志。

    dwStackSize
    堆栈的初始大小,以字节为单位。系统将此值四舍五入到最近的页面。如果此参数为零,则新线程使用可执行文件的默认大小。有关更多信息,请参阅线程堆栈大小。

    lpStartAddress
    指向由线程执行的应用程序定义函数的指针。该指针表示线程的起始地址。有关线程函数的更多信息,请参见 ThreadProc

    lpParameter
    指向要传递给线程的变量的指针。

    dwCreationFlags
    控制线程创建的标志。

    值    含义
    0  :该线程在创建后立即运行。
    CREATE_SUSPENDEDs 0x00000004   : 线程是在挂起状态下创建的,并且在调用ResumeThread函数之前不会运行 。
    STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000:在所述dwStackSize参数指定堆栈的初始保留大小。如果未指定此标志,则dwStackSize指定提交大小。


    lpThreadId
    指向接收线程标识符的变量的指针。如果此参数为 NULL,则不返回线程标识符。

    返回值
    如果函数成功,则返回值是新线程的句柄。

    如果函数失败,则返回值为NULL。要获取扩展错误信息,请调用 GetLastError。

    请注意,即使lpStartAddress指向数据,代码或无法访问,CreateThread也可能成功 。如果线程运行时起始地址无效,则发生异常,并且线程终止。由于无效的起始地址导致的线程终止被视为线程进程的错误退出。此行为类似于CreateProcess的异步特性,即使它引用无效或缺少动态链接库(DLL),也会创建该进程。

    备注
    进程可以创建的线程数受可用虚拟内存的限制。默认情况下,每个线程都有一兆字节的堆栈空间。因此,您最多可以创建2,048个线程。如果减小默认堆栈大小,则可以创建更多线程。但是,如果为每个处理器创建一个线程并构建应用程序队列,应用程序维护上下文信息,则应用程序将具有更好的性能。在处理下一个队列中的请求之前,线程将处理队列中的所有请求。

    使用THREAD_ALL_ACCESS访问权限创建新的线程句柄。如果在创建线程时未提供安全描述符,则使用创建线程的进程的主令牌为新线程构造默认安全描述符。当调用者尝试使用OpenThread函数访问该线程时,将根据此安全描述符评估调用者的有效令牌以授予或拒绝访问权限。

    调用GetCurrentThread 函数时,新创建的线程对自身具有完全访问权限。

    Windows Server 2003: 线程对自身的访问权限是通过根据为线程构造的默认安全描述符评估创建线程的进程的主令牌来计算的。如果在远程进程中创建线程,则使用远程进程的主令牌。因此,在调用GetCurrentThread时,新创建的线程可能会减少对自身的访问权限。某些访问权限(包括THREAD_SET_THREAD_TOKEN和THREAD_GET_CONTEXT)可能不存在,从而导致意外故障。因此,建议不要在模仿其他用户时创建线程。

    如果线程是在可运行状态下创建的(即,如果未使用CREATE_SUSPENDED标志),则线程可以在CreateThread返回之前开始运行,特别是在调用者接收到创建的线程的句柄和标识符之前。

    线程执行从lpStartAddress参数指定的函数开始。如果此函数返回,则DWORD返回值用于在对ExitThread函数的隐式调用中终止线程 。使用 GetExitCodeThread函数获取线程的返回值。

    创建的线程的线程优先级为THREAD_PRIORITY_NORMAL。使用 GetThreadPriority和 SetThreadPriority函数来获取和设置线程的优先级值。

    当线程终止时,线程对象获得信号状态,满足在对象上等待的任何线程。

    线程对象保留在系统中,直到线程终止并且通过调用CloseHandle关闭了它的所有句柄。

    ExitProcess, ExitThread, CreateThread, CreateRemoteThread的功能,以及正在启动的处理(如通过一个调用的结果 CreateProcess)的过程中是彼此之间串行化。这些事件中只有一个可以一次发生在地址空间中。这意味着以下限制包含:

    在进程启动和DLL初始化例程期间,可以创建新线程,但是在为进程执行DLL初始化之前它们不会开始执行。 
    进程中只有一个线程可以一次处于DLL初始化或分离例程中。 
    在DLL初始化或分离例程中没有线程之前,ExitProcess不会完成。 
    调用C运行时库(CRT)的可执行文件中的线程应使用_beginthreadex和_endthreadex函数进行线程管理,而不是 CreateThread和 ExitThread ; 这需要使用CRT的多线程版本。如果使用CreateThread创建的线程调用CRT,则CRT可以在低内存条件下终止进程。 
    Windows Phone 8.1: Windows Phone 8.1及更高版本上的Windows Phone应用商店支持此功能。

    Windows 8.1和Windows Server 2012 R2:Windows 8.1,Windows Server 2012 R2及更高版本上的Windows应用商店应用程序支持此功能。
     

     

    展开全文
  • 2、COM组件是以WIN32动态链接(DLL)或可执行文件(EXE)形式发布的可执行代码组成。 3、COM组件是遵循COM规范编写的 4、COM组件必须是动态链接的 5、COM组件不是一种计算机语言 6、COM组件不是DLL,只是利用DLL来给...

    一、什么是COM组件

    1、COM是Component Object Model (组件对象模型)的缩写
    2、COM组件是以WIN32动态链接库(DLL)或可执行文件(EXE)形式发布的可执行代码组成。
    3、COM组件是遵循COM规范编写的
    4、COM组件必须是动态链接的
    5、COM组件不是一种计算机语言
    6、COM组件不是DLL,只是利用DLL来给组件提供动态链接的能力
    7、COM组件不是一个API函数集。
    8、COM组件不是类,COM 就是一套接口规范,就好象交通规则一样
    9、可以供多种语言调用,跨语言的调用
    10、COM中的接口是一组由组件实现的提供给客户使用的函数。基于二进制接口
    《Inside C++ Object Model》
    《COM本质论》
    《COM+技术内幕》

    511遇见易语言多线程大漠多线程

    二、认识大漠插件

    Dm.dll插件目前是用COM架构设计的,属于第三方COM对象,要想在我们自己的程序里引用(同进程内调用),需要注册,或免注册直接调用。
    大漠综合插件(dm.dll)采用vc6.0编写,是一款集前后台,文字识别,图色,键鼠,窗口,内存,DX,Call等功能于一身的综合插件。主要用于按键精灵、简单游、易语言等辅助制作工具,具有识别速度超级快的特点! 采用COM接口编写,适用于所有语言调用。

    三、初始化COM

    1、CoInitialize

    CoInitialize是Windows提供的API函数,用来告诉 Windows以单线程的方式创建com对象。
    应用程序调用com库函数(除CoGetMalloc(获取对默认的OLE任务内存分配器指针)和内存分配函数)之前必须初始化com库。

    CoInitialize(0)

    多线程里创建COM对象前先初始化,一个线程只调用一次,

    CoInitialize(0)
    dm.创建 ()

    2、CoInitializeEx

    是 Windows提供的API函数,为当前线程初始化COM库并设置并发模式 。应用程序调用com库中的函数(除CoGetMalloc和内存分配函数)之前必须初始化com库。

    CoInitializeEx(0,0)

    函数原型

    HRESULT CoInitializeEx(
    void * pvReserved,
    DWORD dwCoInit
    );
    <strong class="text-danger"> 参数介绍:</strong>
    pvReserved
    系统 保留的参数,必须传入 NULL.
    dwCoInit

    该标示指明基于当前线程的并发模式和初始化选项。该参数是 COINIT 枚举类型,传入参数时候,除了
    COINIT_APARTMENTTHREADED 和COINIT_MULTITHREADED标记外,其余的标记可以组合使用。
    在应用程序中使用COM库,至少要调用一次CoInitializeEx函数(通常也就调用一次)。如果传入参数的并发标志相同,单个线程也可以多次调用该函数

    3、CoUninitialize

    关闭当前线程的COM库,卸载线程加载的所有dll,释放任何其他的资源,关闭在线程上维护所有的连接。
    CoInitialize、CoInitializeEx都是windows的API,主要是告诉windows以什么方式为程序创建COM对象。
    有哪些方式呢?单线程和多线程。
    CoInitialize指明以单线程方式创建。
    CoInitializeEx可以指定以多线程方式创建。
    创建单线程方式的COM服务器时不用考虑串行化问题,多线程COM服务器就要考虑。
    在使用中,使用CoInitialize创建可使对象直接与线程连接,得到最高的性能。
    创建多线程对象可以直接接收所有线程的调用,不必像单线程那样需要消息排队,但却需要COM创建线程间汇集代理,这样访问效率高。
    CoInitialize对windows来说可能只是设置一个标志
    CoUninitialize可能只是清除标志。

    CoInitialize和CoUninitialize最好在应用程序初始化以及退出时调用,样例中在构造以及析构中调用是不提倡的做法。

    当调用CoUninitialize这个函数的时候,会关掉其所做的线程。那么如果你的应用在运行的时候只有一个进程,而且该进程也仅有一个线程的话,那么调用该函数自然会导致整个应用的退出。

    根据线程模型划分,进程内COM组件分为四类:Single,Apartment,Free,Both

    COM套间类型为两类:STA和MTA,STA是单线程套间,只能运行一个线程,但是一个进程内可以创建多个STA,STA总是与一个线程相关联,其中第一次创建的STA通常成为主STA(Main STA);MTA是多线程套间,一个进程内只能有一个MTA,但是MTA允许运行多个线程。
    一个线程要进入到STA中还是MTA中,是由线程内调用CoInitializeEx函数的第二个参数决定的。
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);进入到STA(相当于调用CoInitialize(NULL);)
    CoInitializeEx(NULL, COINIT_MULTITHREADED);进入到MTA

    注意:在不再需要的时候,调用CoUninitialize();退出套间,一般CoInitializeEx与CoUninitialize都需要成对调用,以释放COM占用的资源。

    四、CoInitializeEx 与CoInitialize的区别

    1、多线程崩溃和使用CoInitialize或CoInitializeEX没有关系
    这里也不能说CoInitializeEX(0,0)更适合易语言,而是更适合高并发。
    因为CoInitializeEX内部有锁机制,效率更慢,而需要用内存换效率。
    2、多线程和高并发不是一回事极端高并发下崩溃
    3、所以,在某种环境下,两者是一致的。 而高并发可能让CoInitialize堵塞了
    4、后来的应使用CoInitializeEX,但是调用大量早期的历史Com库,是使用的CoInitialize
    5、有的时候,高并发崩溃了,真的没有办法,因为那超过了机器的处理能力,只能限制。
    虽然我们动不动就多线程的说法,但是,实际上我们的CPU常见的也就是4核心。那么真正在运行的也就是4条线程
    所以,线程数量,不是越多越好的。切换时间片的时间,都够执行很多的代码了。线程多了反而造成了资源的浪费
    如果真的需要1400条线程去运行,那你的确需要CoInitializeEX(0,8)确保安全和使用更多的内存
    但是,如果只是几条线程,或者几十条线程,用CoInitialize可以运行的更快,和少占用资源
    MSDN也是推荐CoInitializeEX的,那为啥,还是有人选择CoInitialize呢,存在即合理的
    为什么CoInitialize效率快的,高并发下反而卡死了,占用资源更多呢?
    那是因为,他运行的快,无锁,使用了更多的CPU资源
    所以,2个都是可以的,看自己的应用场景取舍。更倾向CoInitialize
    但是,如果需要高并发,而客户机器配置也很强大,也会选择CoInitializeEX
    1、问题的重点是,同一套代码,用CoInitialize(0)或者CoInitializeEX(0,2)高并发下程序会崩溃,而用CoInitializeEX(0,0)就不会,测试程序的代码只有几行,是易语言开发者常用的计算js的方式,是精易模块里大量使用的方式,不管您认为是代码问题还是易语言本身问题,用CoInitializeEX(0,0)不崩溃是事实,如果一定要说有错,那么是否可以说CoInitializeEX(0,0)更适合易语言,更适合易语言开发者?
    2、多并发和多线程不是一回事,线程安全跟是否支持高并发也不是一回事
    3、汇编那个我之前就看了,他实际上说的是 CoInitializeEX(0,2) 等效于 CoInitialize(0)
    4、其它国际化的语言并没有默认使用CoInitialize(0),恰恰相反的是CoInitializeEX在其他编程语言中运用还是比较广泛的,CoInitializeEX默认的参数就是CoInitializeEX(0,0),而CoInitialize(0)相当于 CoInitializeEX(0,2)
    5、只要windows系统没有崩溃,黑屏或者蓝屏,而程序崩溃了,那必然是有原因的,有冲突的,这个冲突的地方并不难找到,任何崩溃的问题是应该并且可以得到解决的
    CoInitialize、CoInitializeEx都是windows的API,主要是告诉windows以什么方式为程序创建COM对象,原因是程序调用com库函数(除CoGetMalloc和内存分配函数)之前必须初始化com库。

    有哪些方式呢?单线程和多线程。
    CoInitialize指明以单线程方式创建。
    CoInitializeEx可以指定COINIT_MULTITHREADED以多线程方式创建。
    创建单线程方式的COM服务器时不用考虑串行化问题,多线程COM服务器就要考虑。
    在使用中,使用CoInitialize创建可使对象直接与线程连接,得到最高的性能。创建多线程对象可以直接接收所有线程的调用,不必像单线程那样需要消息排队,但却需要COM创建线程间汇集代理,这样访问效率不高。

    五、COM组件注册

    一个COM组件在使用前必须首先注册

    手动注册

    运行 (“regsvr32 ” + 取运行目录 () + “\dm.dll” + “ -s”, 真, )
     
    获得管理员权限运行bat
     
    cd /d %~dp0是什么意思啊?
    是dos的批处理命令。
     
    意思是 
    更改当前目录为批处理本身的目录 
    有些晕吧?不急,我举例 
    比如你有个批处理a.bat在D:\qq文件夹下 
    a.bat内容为 
    cd /d %~dp0 
    在这里 
    cd /d %~dp0的意思就是cd /d d:\qq 
    %0代表批处理本身 d:\qq\a.bat 
    ~dp是变量扩充 
    d既是扩充到分区号 d: 
    p就是扩充到路径 \qq 
    dp就是扩充到分区号路径 d:\qq

    源码:511遇见易语言多线程大漠多线程-20初始化COM库

    展开全文
  • C语言多线程,动态库和静态库

    千次阅读 2016-06-11 10:52:38
    C语言多线程,动态库和静态库
  • 多线程 图片显示 基本控件 动态链接 定时器 MFC
  • 使用mybatisplu的动态切换数据源时,遇到无法切换的问题 原因是具体操作的服务调用的是异步线程 mp的切换数据源信息是放在ThreadLocal去存储的,如果切换了线程,那么就取不到数据源信息的内容,导致无法切换数据...
  • 一个很好用的modbus动态库源代码及modbus协议全文 代码写的很好,而且支持linux,可以方便的移植到嵌入式系统
  • Go学习笔记—多线程

    千次阅读 2021-12-01 10:27:19
    多线程编程 ​ 一个进程可以包含多个线程,这些线程运行的一定是同一个程序(进程==程序),且都由当前进程已经存在的线程通过系统调用的方式创建出来。进程是资源分配的基本单位,线程是调度运行的基本单位,线程...
  • OpenBLAS多线程使用教程

    千次阅读 2019-11-11 13:30:19
    )给出了另外两种单线程方法,推测同理可设置多线程,但是没有继续尝试。 可以将23步改成: a. make USE_THREAD= 4 (4自己设置线程数, 取0为单线程 ) b. ./dgemv_test.out openblas_set_num_threads 2 ...
  • 但是由于项目初期对CxImage开源的编译问题,导致该开源在MFC下无法正常运行,因此决定将功能函数在控制台下完成,然后封装成动态链接(XXX.dll),并加载到MFC工程。下面是对“急救车上的多种医疗设备数据...
  • DLL的多线程

    万次阅读 2016-04-06 11:02:35
    VC++动态链接编程之多线程 在DLL可以处理多线程,WIN32对于多线程的支持是操作系统本身提供的一种能力,并不在于用户编写的是哪一类程序。即便是一个控制台程序,我们都可以使用多线程: #include #...
  • 需求需要查询多个SQL...但是使用并行的方式进行查询,即多线程查询,所消耗的时间为查询最久SQL的时间。 此处使用callable + furtherTask 方式实现 Callable<List<Map<String, String>>> ma...
  • 操作系统 --- 多线程(初阶)

    千次阅读 多人点赞 2022-03-16 14:03:45
    多线程(初阶) 1. 线程 1.1 为什么会有线程 上一节进程的课程我们学习了,引入进程就是为了"并发编程",虽然进程能解决并发的问题,但是我们认为还不是不够理想. 因为创建进程/销毁进程/调度进程,开销有点大, 创建进程...
  • 多线程常见的面试题

    千次阅读 2020-09-16 16:21:58
    多线程常见的面试题: 1. 什么是线程和进程? 线程与进程的关系,区别及优缺点? 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。 ...
  • 进程引用动态链接库的全局变量问题 现象描述: 前提:存在一个动态库libvlan.so,存在一个应用console。 做法:在console调用libvlan.so的两个APIs,...结论:动态库中的全局变量,在被其他进程使用...
  • 本文主要讲解Linux系统下的多线程编程技术,包括线程的基本概念、线程的基本操作、多线程编程存在的问题,什么是临界区等内容。
  • 内含多个动态链接 dll 的经典实例(delphi),封装了单元,做软件用到多线程时,复制一下这个代码就行了,非常方便好用。网上delphi动态链接的实例比较少,有了这个,就不用怕了!!..
  • Linux多线程

    千次阅读 2022-03-07 10:04:20
    线程一、线程是什么二、线程的优缺点线程的优点线程的缺点线程异常线程用途进程和线程对比三、线程的操作 一、线程是什么 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的...
  • C/C++:进程使用dlopen、dlsym、dlclose装载动态库
  • 一种语言的开发环境往往会附带有语言,这些就是对操作系统的API的包装,我们也称这些语言为运行 对于MSVC的运行(CRT)...在调试模式下,使用调试运行多线程调试(/MTd)、多线程调试DLL(/MDd) 在发...
  • Python解释执行原理我是一个Python线程,我的工作就是解释执行程序员编写的Python代码。之所以说是解释执行,是因为Python是高级语言,CPU那家伙不认识Python代码,需要运行的时候动态翻译成CPU指令。我把Python源...
  • 和其它多线程一样,不能在IDE环境调试,只能编译EXE后再调试。 特别声明:此DLL仅限于VB爱者研究使用使用者请注明出处(首发于VBGOOD 链接地址http://www.vbgood.com/thread-108165-1-1.html),不得用于商业用途...
  • 需求背景:DLL接口自身是向主调方提供服务,考虑到主调方的不定性以及响应速度问题,需要支持多线程。实现思路:DLL在初次加载或者被唤醒的时候会调用DLLMain函数(Delphi的Main函数头已被隐藏,实际上就是主文件的...
  • 第1部分 c++多线程系统编程第1章 线程安全的对象生命期管理1. 多个线程同时看到一个对象时,析构可能出现race condition 2. 线程安全的类的定义:多个线程同事访问时,其表现出正确的行为;无论操作系统如何调度这些...
  • 线程的定义,进程和线程的关系2.Linux下的线程Linux原生线程库(pthread) 1.线程的定义,进程和线程的关系 线程是“一个进程内部的控制序列”一切进程至少都有一个执行线程。 根据上图可知: 线程在进程内部运行...
  • nodejs中使用多线程编程的方法实例

    千次阅读 2015-05-26 23:50:28
    这篇文章主要介绍了nodejs中使用多线程编程的方法实例,本文使用nodejs addon借助c/c++的能力扩展nodejs多线程编程,需要的朋友可以参考下 在以前的博文别说不可能,nodejs中实现sleep中,我向大家介绍了nodejs ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 249,864
精华内容 99,945
关键字:

动态库中使用多线程