win32线程API

在Windows平台下可以通过Windows的线程库来实现多线程编程。

对于多线程程序可以使用Visual Studio调试工具进行调试,也可以使用多核芯片厂家的线程分析调试工具进行调试。

Win32 API(了解Windows,代码小,效率高)

  • Windows操作系统为内核以及应用程序之间提供的接口
  • 将内核提供的功能进行函数封装
  • 应用程序通过调用相关的函数获得相应的系统功能

_beginthread

  • _beginthread(函数名,栈大小,参数指针)
  • Win32 函数库中提供了操作多线程的函数, 包括创建线程、管理线程、终止线程、线程同步等接口。

    线程函数(线程开始执行的函数)

    DWORD WINAPI ThreadFunc (LPVOID

    lpvThreadParm );

    线程创建

    HANDLE CreateThread (

    LPSECURITY_ATTRIBUTES lpThreadAttributes,

    SIZE_T dwStackSize,

    LPTHREAD_START_ROUTINE lpStartAddress,

    LPVOID lpParameter,

    DWORD dwCreationFlags,

    LPDWORD lpThreadId );
  • 第一个参数lpThreadAtt,是一个指向SECURITY- ATTRIBUTES结构的指针,该结构制定了线程的安全属性,缺省为 NULL。

    第二个参数dwStackSize,是栈的大小,一般设置为0。

    第三个参数lpFun是新线程开始执行时,线程函数的入口地址。它必须是将要被新线程执行的函数地址,不能为NULL。

    第四个参数lpParameter,是线程函数定义的参数。可以通过这个参数传送值,包括指针或者NULL 。

    第五个参数dwCreationFlags,控制线程创建的附加标志,可以设置两种值。0表示线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;

    第六个参数lpThreadID,为指向32位变量的指针,该参数接受所创建线程的ID号。如果创建成功则返回线程的ID,否则返回NULL。
  • CreateThread不会执行C运行时数据块, 因此在C运行时库的应用程序中,不能使用CreateThread创建线程,

    微软提供了另外的创建线程的方法:创建线程用process.h头文件中声明的C执行时期链接库函数_beginthread。

    语法:

    hThread = _beginthread (

    void( __cdecl *start_address )( void * ),

    unsigned stack_size, void *arglist) ;

    线程函数的语法:

    void __cdecl ThreadProc (void * pParam) ;
#include "stdio.h"
#include <windows.h>
#include <process.h>
#include <iostream>
#include <fstream>
using namespace std; //使用_beginthread函数创建线程的例子。 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(5000);
cout << "end" << endl;
return 0;
}

创建执行挂起终止

  • CreateThread(NULL, 0, FunOne, (void*)&input, CREATE_SUSPENDED, NULL);

  • 安全属性 栈大小 线程函数 参数指针 附加标志 ID号(32位int指针)

  • 附加标志为0 创建即可执行

  • 附加标志为CREATE_SUSPENDED 创建就要挂起

  • ResumeThread(句柄) 挂起计数器-1,为0则进行

  • SuspendThread(句柄) 挂起计数器+1

  • TerminateThread(hand1, 1) 第二个参数为exitcode

  • 调用SetThreadPriority函数设置线程的相对优先级,例如

    Bool SetThreadPriority (HANDLE hPriority , int nPriority)

    参数hPriority 指向待设置的线程句柄

  • nPriority 是线程的相对优先级,可以是以下的值:

    空闲:THREAD - PRIORITY- IDLE 15

    最低线程:THREAD - PRIORITY- LOWEST 2

    低于正常线程:THREAD - PRIORITY- BELOW- NORMAL 1

    正常线程:THREAD - PRIORITY- NORMAL 0

    高于正常线程:THREAD - PRIORITY- ABOVE – NORMAL -1

    最高线程:THREAD - PRIORITY- HIGHEST -2

    关键时间:THREAD - PRIORITY- TIME – CRITICAL -15

  • 挂起与恢复函数原型

    DWORD SuspendThread(HANDLE hThread);

    挂起指定的线程(慎用,不处理同步对象)

    如果函数执行成功,则线程的执行被终止

    每次调用SuspendThread() 函数,线程将挂起计数器的值增1

    DWORD ResumeThread(HANDLE hThread);

    结束线程的挂起状态来执行这个线程

    每次调用ResumeThread() 函数,线程将挂起计数器的值减1

    若挂起计数器的值为0,则不会再减

#include "stdio.h"
#include <windows.h>
#include <iostream>
using namespace std; //简单的多线程创建、执行、挂起、终止的程序例子。 DWORD WINAPI FunOne(LPVOID param) {
while (true)
{
Sleep(1000);
cout << "hello! ";
//cout<<"hello! "<<*((int*)param);
}
return 0;
}
DWORD WINAPI FunTwo(LPVOID param) {
while (true)
{
Sleep(1000);
cout << "world! ";
}
return 0;
} //注意创建线程函数的第五个参数的运用。
//输入1和2数字,可以控制线程的启动和终止。
//注意连续输入1和2数字线程的运行情况。
//线程的终止函数。 int main(int argc, char* argv[])
{
int input = 0; //创建线程。这里第四个参数值设为NULL也可以,因为线程函数里没有使用输入参数。
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);
}
if (input == 2)
{
//挂起线程
SuspendThread(hand1);
SuspendThread(hand2);
}
if (input == 0)
{
//终止线程
TerminateThread(hand1, 1);
TerminateThread(hand2, 1);
}
if (input == 9)
return 0;
}; return 0; }

利用全局变量实现同步

这样做可能会有一个问题,主线程结束时其他线程也就跟着结束了

  • 全局变量

    进程中的所有线程均可以访问所有的全局变量,因而全局变量成为Win32多线程通信的最简单方式。

    int var; //全局变量

    UINT ThreadFunction ( LPVOID pParam {

    while (var)

    {

    …… //线程处理

    }

    return 0; }

    var是一个全局变量,任何线程均可以访问和修改。线程间可以利用此特性达到线程同步的目的。
#include "stdio.h"
#include <windows.h>
#include <iostream>
using namespace std; //使用全局变量同步线程的例子。 //全局变量。
int globalvar = false; DWORD WINAPI ThreadFunc(LPVOID pParam)
{
cout << " ThreadFunc " << endl;
Sleep(100); //修改全局变量的值。
globalvar = true; return 0;
}
DWORD WINAPI ThreadFunc1(LPVOID pParam)
{
while (1)
cout << " ThreadFunc111 " << endl;
return 0;
}
DWORD WINAPI ThreadFunc2(LPVOID pParam)
{
while (1)
cout << " ThreadFunc222 " << endl;
return 0;
} //这种方式可能存在一些问题。 int main()
{
HANDLE hthread1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL);
HANDLE hthread2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL);
HANDLE hthread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
if (!hthread)
{
cout << "Thread Create Error ! " << endl;
CloseHandle(hthread);
}
bool b =SetThreadPriority(hthread,15);
cout<<GetThreadPriority(hthread1)<<endl;
cout<<GetThreadPriority(hthread2)<<endl;
cout<<GetThreadPriority(hthread)<<endl; //循环判断全局变量的值。
while (!globalvar)
cout << "Thread while" << endl; cout << "Thread exit" << endl;
return 0;
}
Thread while  ThreadFunc111
ThreadFunc111
ThreadFunc111
ThreadFunc111 ThreadFunc222
ThreadFunc222
ThreadFunc222
ThreadFunc222
Thread while
Thread while
Thread while
Thread while ThreadFunc222
ThreadFunc222
ThreadFunc111 Thread while
Thread while ThreadFunc222 ThreadFunc111
Thread exit
ThreadFunc111 ThreadFunc222 ThreadFunc222 ThreadFunc111
ThreadFunc111
ThreadFunc222
ThreadFunc111

利用事件实现同步

  • 事件是WIN32提供的最灵活的线程间同步方式。

    事件存在两种状态:

    激发状态(signaled or true)

    未激发状态(unsignal or false)

    事件可分为两类:

    手动设置:这种对象只能用程序来手动设置,在需要该事件或者事件发生时,采用SetEvent及ResetEvent来进行设置。

    SetEvent只有一个参数,该参数指定了事件对象的句柄值,若事件成功激发,返回TRUE;

    ResetEvent函数将事件对象恢复到最初的非激发状态,只有一个参数,成功后返回真

    自动恢复:一旦事件发生并被处理后,自动恢复到没有事件状态,不需要再次设置。

  • CreateEvent(NULL, FALSE, FALSE, NULL);

  • 第一个参数还是安全,默认为NULL,二参代表事件类型,true为手动清除信号,false为自动清除

  • 三参:事件的初始状态 四参:事件的名称

  • setEvent(句柄)

  • WaitForSingleObject(evRead, INFINITE);等待某个事件

    WaitForSingleObject (evFinish, INFINITE)

    参数1:等待对象

    参数2:等待时间

    返回值:WAIT_OBJECT_0(激发)

    WAIT_TIMEOUT(超时)

    WAIT_FAILED(错误)

  • WaitForMultipleObjects(2 ,evFin ,TRUE ,INFINITE)

    参数1:等待的句柄数

    参数2:等待的句柄数组

    参数3:确定是否等待所有句柄激发后才返回

    参数4:等待时间

    返回值: WAIT_OBJECT_I(激发事件在句柄数组中的索引)

  • 例子:有三个线程

    主线程、读线程ReadThread、写线程WriteThread

    读线程ReadThread必须在写线程WriteThread 的写操作完成之后才能进行读操作

    主线程必须在读线程ReadThread 的读操作完成后才结束

    定义两个事件对象evRead,evFinish

    evRead由写线程WriteThread用于通知读线程ReadThread 进行读操作

    evFinish由读线程ReadThread用于通知主线程读操作已经结束

#include "stdio.h"
#include <windows.h>
#include <iostream>
using namespace std; //**使用事件机制同步线程的例子。 //两个事件。
HANDLE evRead, evFin;
HANDLE evWrite; void ReadThread(LPVOID param)
{
//等待读事件。
WaitForSingleObject(evRead, INFINITE); cout << "Reading" << endl;
//ResetEvent(evRead);//evRead为手动恢复类型时打开
SetEvent(evWrite);
WaitForSingleObject(evRead, INFINITE);
cout << "Reading11111" << endl; //激活结束事件。
SetEvent(evFin);
}
void WriteThread(LPVOID param)
{
cout << "Writing" << endl; //激活读事件。
SetEvent(evRead); WaitForSingleObject(evWrite, INFINITE);
cout << "Writing11111" << endl;
SetEvent(evRead);
}
int main(int argc, char* argv[])
{
//创建两个事件,注意事件参数的含义。
evRead = CreateEvent(NULL, FALSE, FALSE, NULL);
evFin = CreateEvent(NULL, FALSE, FALSE, NULL); evWrite = CreateEvent(NULL, FALSE, FALSE, NULL);
//evRead = CreateEvent (NULL ,TRUE ,FALSE ,NULL) ;//修改第二个参数为TRUE
//evFin = CreateEvent (NULL ,TRUE ,FALSE ,NULL) ;//修改第二个参数为TRUE
//evWrite = CreateEvent (NULL ,TRUE ,FALSE ,NULL) ;//修改第二个参数为TRUE _beginthread(ReadThread, 0, NULL);
_beginthread(WriteThread, 0, NULL); //等待结束事件。
WaitForSingleObject(evFin, INFINITE); cout << "The Program is End" << endl;
return 0;
}

临界区

  • 防止多个线程同时执行一个特定代码段的机制

    适用于多个线程操作之间没有先后顺序,但要求互斥的同步

    多个线程访问同一个临界区的原则:

    一次最多只能一个线程停留在临界区内

    不能让一个线程无限地停留在临界区内,否则其它线程将不能进入该临界区

    定义临界区变量的方法如下:

    CRITICAL_SECTION gCriticalSection;

    通常情况下,CRITICAL_SECTION结构体应该被定义为全局变量,便于进程中的所有线程可以方便地按照变量名来引用该结构体。
  • 初始化临界区

    VOID WINAPI InitializeCriticalSection (

    LPCRITICAL_SECTION lpCriticalSection );

    删除临界区

    VOID WINAPI DeleteCriticalSection (

    LPCRITICAL_SECTION lpCriticalSection );

    进入临界区

    VOID WINAPI EnterCriticalSection (

    LPCRITICAL_SECTION lpCriticalSection );

    执行该语句时,程序会判断cs对象是否已被锁定,若没锁定则线程进入临界区,并将cs置为锁定状态;否则,线程线程被阻塞以等待cs解锁。

    离开临界区

    VOID WINAPI LeaveCriticalSection (

      LPCRITICAL_SECTION lpCriticalSection );

    线程执行该语句后,程序自动将cs解锁,并唤醒等待cs解锁的线程
  • 使用临界区编程的一般方法是:

    void WriteData()

    {

    EnterCriticalSection(&gCriticalSection);

    //do something

    LeaveCriticalSection(&gCriticalSection);

    }

    例子

    假如一个银行系统有两个线程执行取款任务,一个使用存折在柜台取款,一个使用银行卡在ATM取款。若不加控制,很可能账户余额不足两次取款的总额,但还可以把钱取走。
#include "stdio.h"
#include <windows.h>
#include <iostream>
#include <process.h>
#include <iostream>
#include <fstream>
using namespace std; //**使用临界区机制同步线程。 int total = 100;
HANDLE evFin[2];
CRITICAL_SECTION cs;//临界区。 //可以去掉临界区机制,查看是否出现错误。(需要辅助sleep函数)
void WithdrawThread1(LPVOID param)
{
EnterCriticalSection(&cs);//进入临界区
if (total - 90 >= 0)
{//Sleep(100);
total -= 90;
cout << "You withdraw 90" << endl;
}
else
cout << "You do not have that much money" << endl;
LeaveCriticalSection(&cs);//退出临界区
SetEvent(evFin[0]);
}
void WithdrawThread2(LPVOID param)
{
EnterCriticalSection(&cs);//进入临界区
if (total - 20 >= 0)
{
total -= 20;
cout << "You withdraw 20" << endl;
}
else
cout << "You do not have that much money" << endl;
LeaveCriticalSection(&cs);//退出临界区
//LeaveCriticalSection(&cs) ;
SetEvent(evFin[1]);
}
int main(int argc, char* argv[])
{
evFin[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
evFin[1] = CreateEvent(NULL, FALSE, FALSE, NULL); InitializeCriticalSection(&cs);//初始化临界区。 _beginthread(WithdrawThread1, 0, NULL);//创建线程顺序影响执行的结果。
_beginthread(WithdrawThread2, 0, NULL);
//_beginthread(WithdrawThread1 , 0 , NULL) ; int id = WaitForMultipleObjects(2, evFin, TRUE, INFINITE);//等待两个事件都激活。
cout << "句柄数组中的索引:" << id << endl; DeleteCriticalSection(&cs);//删除临界区 cout << total << endl;
return 0;
}

先1后2

先2后1

互斥量

  • 通常用于协调多个线程或进程的活动,通过对资源“锁定”和“取消锁定”,来控制对共享资源的访问。

    当一个互斥量被一个线程锁定了,其他试图对其加锁的线程就会被阻塞;当对互斥量加锁的线程解除锁定后,则被阻塞的线程中的一个会得到互斥量。

    互斥量的作用是保证每次只能有一个线程获得互斥量

    使用CreateMutex函数创建:

    HANDLE CreateMutex(

    LPSECURITY_ATTRIBUTES lpMutexAttributes,

    BOOL bInitialOwner,

    LPCTSTR lpName

    );

    安全属性 是否手动清除(true为手动) 名称
  • 相关的API:

    CreateMutex 创建一个互斥对象,返回对象句柄;

    OpenMutex 打开并返回一个已存在的互斥对象的句柄,使之后续访问;

    ReleaseMutex 释放对互斥对象的占用,使之成为可用;

    使用互斥量的一般方法是:

    void Writedata()

    {

    WaitForSingleObject(hMutex,…);

    ...//do something

    ReleaseMutex(hMutex);

    }
#include "stdio.h"
#include <windows.h>
#include <iostream>
#include <process.h>
#include <iostream>
#include <fstream>
using namespace std; //**互斥量的使用方法。 #define THREAD_INSTANCE_NUMBER 3 LONG g_fResourceInUse = FALSE;
LONG g_lCounter = 0; DWORD ThreadProc(void* pData) { int ThreadNumberTemp = (*(int*)pData);
HANDLE hMutex; if ((hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "Mutex.Test")) == NULL) {
cout << "Open Mutex error!" << endl;
} //cout << "ThreadProc is running hMutexxxxxxx!!" << ThreadNumberTemp <<endl;
WaitForSingleObject(hMutex, INFINITE);//获取互斥量。
cout << "ThreadProc is running!!" << ThreadNumberTemp << endl;
cout << "ThreadProc gets the mutex-" << ThreadNumberTemp << endl; ReleaseMutex(hMutex);//释放互斥量。
CloseHandle(hMutex);
return 0;
} int main(int argc, char* argv[])
{ int i;
DWORD ID[THREAD_INSTANCE_NUMBER];
HANDLE h[THREAD_INSTANCE_NUMBER];
HANDLE hMutex;
if ((hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "Mutex.Test")) == NULL) {
if ((hMutex = CreateMutex(NULL, FALSE, "Mutex.Test")) == NULL) //注意第二个参数,当前线程是否拥有创建的锁
{
cout << "Create Mutex error!" << endl;
return 0;
}
}
//ReleaseMutex(hMutex); //CreateMutex函数第二参数为TRUE时打开 //获取信号量的位置不同,将产生不同的结果。
//WaitForSingleObject(hMutex,INFINITE);
for (i = 0; i < THREAD_INSTANCE_NUMBER; i++)
{
WaitForSingleObject(hMutex, INFINITE);//获取互斥量。本线程可重复获取,但解锁时需释放相同的次数。
h[i] = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)ThreadProc,
(void*)&ID[i],
0,
&(ID[i]));
//WaitForSingleObject(hMutex,INFINITE);//演示重复获取互斥量
if (h[i] == NULL)
cout << "CreateThread error" << ID[i] << endl;
else
cout << "CreateThread: " << ID[i] << endl;
ReleaseMutex(hMutex);
//Sleep(1000);
}
//ReleaseMutex(hMutex);//ReleaseMutex(hMutex);ReleaseMutex(hMutex);//演示释放重复获取的互斥量 WaitForMultipleObjects(THREAD_INSTANCE_NUMBER, h, TRUE, INFINITE);
cout << "Close the Mutex Handle! " << endl;
CloseHandle(hMutex); return 0;
}

信号量

  • 信号量是一个核心对象,拥有一个计数器,可用来管理大量有限的系统资源

    当计数值大于零时,信号量为有信号状态

    当计数值为零时,信号量处于无信号状态

    创建信号量

    HANDLE CreateSemaphore (PSECURITY_ATTRIBUTE psa,

    LONG lInitialCount, LONG lMaximumCount, PCTSTR pszName);

    安全属性 初始数量 最大数量 信号量名称
  • 释放信号量

    BOOL WINAPI ReleaseSemaphore(HANDLE hSemaphore,

    LONG lReleaseCount, //信号量的当前资源数增加lReleaseCount

    LPLONG lpPreviousCount);

    打开信号量

    HANDLE OpenSemaphore (DWORD fdwAccess,

    BOOL bInherithandle, PCTSTR pszName );
// exa7.cpp : Defines the entry point for the console application.
// #include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std; //**使用信号量机制同步线程。 #define THREAD_INSTANCE_NUMBER 3 DWORD foo(void * pData) { int ThreadNumberTemp = (*(int*) pData);
HANDLE hSemaphore; if ((hSemaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Semaphore.Test")) == NULL) {
cout << "Open Semaphore error!" << endl;
} WaitForSingleObject(hSemaphore,INFINITE);//获取信号量。 cout << "foo is running!!!" << ThreadNumberTemp << endl;
cout << "foo gets the semaphore-" << ThreadNumberTemp<< endl; ReleaseSemaphore(hSemaphore, 1, NULL);//释放一个单位的信号量 CloseHandle(hSemaphore);
return 0;
} int main(int argc, char* argv[])
{ int i;
DWORD ThreadID[THREAD_INSTANCE_NUMBER];
HANDLE hThread[THREAD_INSTANCE_NUMBER];
HANDLE hSemaphore; if ((hSemaphore = CreateSemaphore(NULL,1,1, "Semaphore.Test")) == NULL ) {
cout << "Create Semaphore error!" << endl;
return 0;
} //与互斥量一样,这里获取信号量的位置不同,会产生不同的结果。
for (i=0;i<THREAD_INSTANCE_NUMBER;i++)
{
WaitForSingleObject(hSemaphore,INFINITE);//获取信号量。不可重入。
hThread[i] = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE) foo,
(void *)&ThreadID[i],
0,
&(ThreadID[i])); if (hThread[i] == NULL) cout << "CreateThread error" << ThreadID[i] << endl;
else
cout << "CreateThread: " << ThreadID[i] << endl; ReleaseSemaphore(hSemaphore, 1, NULL);
} WaitForMultipleObjects(THREAD_INSTANCE_NUMBER,hThread,TRUE,INFINITE);
cout << "Close the Semaphore Handle! " << endl;
CloseHandle(hSemaphore); return 0;
}

win32API多线程编程的更多相关文章

  1. Web Worker javascript多线程编程(一)

    什么是Web Worker? web worker 是运行在后台的 JavaScript,不占用浏览器自身线程,独立于其他脚本,可以提高应用的总体性能,并且提升用户体验. 一般来说Javascript ...

  2. Web Worker javascript多线程编程(二)

    Web Worker javascript多线程编程(一)中提到有两种Web Worker:专用线程dedicated web worker,以及共享线程shared web worker.不过主要讲 ...

  3. windows多线程编程实现 简单(1)

    内容:实现win32下的最基本多线程编程 使用函数: #CreateThread# 创建线程 HANDLE WINAPI CreateThread( LPSECURITY_ATTRIBUTES lpT ...

  4. Rust语言的多线程编程

    我写这篇短文的时候,正值Rust1.0发布不久,严格来说这是一门兼具C语言的执行效率和Java的开发效率的强大语言,它的所有权机制竟然让你无法写出线程不安全的代码,它是一门可以用来写操作系统的系统级语 ...

  5. windows多线程编程星球(一)

    以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...

  6. Java多线程编程核心技术---学习分享

    继承Thread类实现多线程 public class MyThread extends Thread { @Override public void run() { super.run(); Sys ...

  7. python多线程编程

    Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...

  8. 浅述WinForm多线程编程与Control.Invoke的应用

    VS2008.C#3.0在WinForm开发中,我们通常不希望当窗体上点了某个按钮执行某个业务的时候,窗体就被卡死了,直到该业务执行完毕后才缓过来.一个最直接的方法便是使用多线程.多线程编程的方式在W ...

  9. Java—多线程编程

    一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径. 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程.一个线程不能独立的存 ...

随机推荐

  1. [VB.NET Tips]字符串转换为日期

    有些字符串需要转换成日期,或者整型转换为日期,可以参考如下思路: Dim result As Date Dim source As String = "20190515" resu ...

  2. [Design Patterns] 01. Creational Patterns - Abstract Factory

    设计模式是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结,使用设计模式的目的是提高代码的可重用性,让代码更容易被他人理解,并保证代码可靠性.它是代码编制真正实现工程化. 四个关键元素 ...

  3. 用Python帮你实现IP子网计算

    目录 0. 前言 1. ipaddress模块介绍 1.1 IP主机地址 1.2 定义网络 1.3 主机接口 1.4 检查address/network/interface对象 1.4.1 检查IP版 ...

  4. Scrapy项目 - 数据简析 - 实现斗鱼直播网站信息爬取的爬虫设计

    一.数据分析截图(weka数据分析截图 2-3个图,作业文字描述) 本次将所爬取的数据信息,如:房间数,直播类别和人气,导入Weka 3.7工具进行数据分析.有关本次的数据分析详情详见下图所示:   ...

  5. 浅析java垃圾回收机制

    什么是java程序中的垃圾?什么这些垃圾又是怎样被回收的?为什么会被回收?不进行回收又会怎样?这些问题都是我们要在这篇博客中要解决的问题! 大家都知道,在c语言中,作为程序员,必须得考虑到去怎样回收已 ...

  6. SOFAJRaft—初次使用

    SOFAJRaft-初次使用 SOFAJRaft 是基于 Raft 算法的生产级高性能 Java 实现,支持 MULTI-RAFT-GROUP.应用场景有 Leader 选举.分布式锁服务.高可靠的元 ...

  7. ELK日志分析系统(3)-logstash数据处理

    1. 概述 logspout收集数据以后,就会把数据发送给logstash进行处理,本文主要讲解logstash的input, filter, output处理 2. input 数据的输入处理 支持 ...

  8. d3.js 绘制北京市地铁线路状况图(部分)

    地铁线路图的可视化一直都是路网公司的重点,今天来和大家一起绘制线路图.先上图. 点击线路按钮,显示相应的线路.点击线路图下面的站间按钮(图上未显示),上报站间故障. 首先就是制作json文件,这个文件 ...

  9. python语言程序设计基础(嵩天)第二章课后习题

    p56: *2.1 实例1的修改.改造实例代码1.1,采用eval(input(<提示内容>))替换现有输入部分,并使输出的温度值为整数. 源代码: TempStr=input(" ...

  10. pycharm导入自己写的包的时候,不能识别模块的解决办法

    今天用写selenium脚本的时候导入自己统计目录下的模块时,出错,明明存在但是报错说模块不存在,找了半天终于找到解决方案,顺便记录一下吧 pycharm不会将当前文件目录自动加入自己的sourse_ ...