スレッドの作成と使用 (MFC/C/C++)

目次

1. スレッドを作成するいくつかの方法

1. POSIX スレッド ライブラリ (pthread) を使用する (C)

2. Windows スレッド ライブラリ (Win32 API) を使用する (C)

3. C++11標準ライブラリを使用する

2 番目に、スレッドの適用 (一般的な例、完全なコードが添付されています)

1. CreateThread はスレッドのインスタンスを作成します


1. スレッドを作成するいくつかの方法

C/C++ では、スレッドを作成する方法が数多くあります。一般的に使用される方法のいくつかを以下に示します。

1. POSIX スレッド ライブラリ (pthread) を使用する (C)

        POSIX スレッド ライブラリは、マルチスレッド プログラミング用の標準ライブラリのセットであり、ほとんどの UNIX 系システムで使用できます。スレッドは pthread_create() 関数を使用して作成できます。

// C
#include <pthread.h>

void *threadFunc(void *arg) {
    // 线程的代码逻辑
    return NULL;
}

int main() {
    pthread_t tid;
    pthread_create(&tid, NULL, threadFunc, NULL);
    // 主线程的代码逻辑
    pthread_join(tid, NULL); // 等待子线程执行完毕
    return 0;
}

2. Windows スレッド ライブラリ (Win32 API) を使用する (C)

        Windows オペレーティング システムでは、Win32 API を使用してスレッドを作成できます。スレッドは CreateThread() 関数を使用して作成できます。

(1) CreateThread() のプロトタイプは次のとおりです。

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

パラメータの説明:

  • lpThreadAttributes: スレッドのセキュリティ属性。デフォルトは NULL です。
  • dwStackSize: スレッド スタックのサイズ。デフォルトは 0 です。これは、デフォルトのスタック サイズを使用することを意味します。
  • lpStartAddress: スレッドのエントリ関数アドレス。関数ポインターまたはスレッド関数の名前を指定できます。
  • lpParameter: スレッド関数に渡されるパラメータ。
  • dwCreationFlags: スレッドの作成フラグ。CREATE_SUSPENDED (作成後に一時停止) などの追加オプションを設定できます。
  • lpThreadId: スレッド ID を受け取るポインター。

CreateThread 関数は、新しいスレッドを作成し、そのスレッドにハンドルを返します。このハンドルを通じて、スレッドの終了を待つ、スレッドを一時停止または再開するなど、スレッド上でいくつかの操作を実行できます。

(2) 以下は、CreateThread を使用して新しいスレッドを作成する方法を示す簡単な例です。

// c
#include <windows.h>

DWORD WINAPI threadFunc(LPVOID lpParam) {
    // 线程的代码逻辑
    return 0;
}

int main() {
    HANDLE hThread = CreateThread(NULL, 0, threadFunc, NULL, 0, NULL);
    // 主线程的代码逻辑
    WaitForSingleObject(hThread, INFINITE); // 等待子线程执行完毕
    CloseHandle(hThread);
    return 0;
}

3. C++11標準ライブラリを使用する

        C++11 標準では、スレッドを簡単に作成および管理できる std::thread クラスが導入されました。

// c++
#include <thread>

void threadFunc() {
    // 线程的代码逻辑
}

int main() {
    std::thread t(threadFunc); // 创建线程
    // 主线程的代码逻辑
    t.join(); // 等待子线程执行完毕
    return 0;
}

4、AfxBeginThread(MFC)

        AfxBeginThread は、新しいスレッドを作成するために使用される MFC (Microsoft Foundation Class) 関数です。その意味は、メインスレッドの動作をブロックすることなく、アプリケーション内で新しいスレッドを開始し、バックグラウンドでいくつかのタスクを実行することです。

AfxBeginThread 関数のプロトタイプは次のとおりです。
CWinThread* AfxBeginThread(
AFX_THREADPROC pfnThreadProc,
LPVOID pParam,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = N ULL
);

パラメータの説明:

  • pfnThreadProc: 新しいスレッドで実行されるスレッド関数へのポインタ。
  • pParam: スレッド関数に渡されるパラメータ。
  • nPriority: 新しいスレッドの優先順位。デフォルトは THREAD_PRIORITY_NORMAL です。
  • nStackSize: 新しいスレッドのスタック サイズ。デフォルトは 0 で、デフォルトのスタック サイズが使用されることを示します。
  • dwCreateFlags: スレッド フラグを作成します。デフォルトは 0 です。
  • lpSecurityAttrs: スレッドのセキュリティ属性。デフォルトは NULL です。

AfxBeginThread 関数は CWinThread オブジェクトへのポインターを返します。このオブジェクトは、スレッドの終了の待機、スレッド ID の取得など、新しいスレッドの動作を管理および制御するために使用できます。

つまり、AfxBeginThread関数を使用して新しいスレッドを作成し、その新しいスレッド内で指定された関数を実行することでマルチスレッドプログラミングを実現します。

例:

// 声明一个变量,继承于CWinThread
UINT ReceiveMsgThreadID;
CThreadReceiveRespMsg *pThreadReceiveMsg;

//启动线程	
pThreadReceiveMsg = (CThreadReceiveRespMsg *)::AfxBeginThread(RUNTIME_CLASS(CThreadReceiveRespMsg), THREAD_PRIORITY_NORMAL);
if (pThreadReceiveMsg != NULL)
{
	log(_T("线程1启动成功 \n"));
	ReceiveMsgThreadID = pThreadReceiveMsg->m_nThreadID;
}
else
{
	log(_T("线程1启动失败 \n"));
}

上記は、スレッドを作成するために一般的に使用されるいくつかの方法です。どの方法を選択するかは、ニーズと動作環境によって異なります。

2 番目に、スレッドの適用 (一般的な例、完全なコードが添付されています)

1. CreateThread はスレッドのインスタンスを作成します

// 头文件
#pragma once
#include "singleton.h"
#include <windows.h>

class CThreadBase
{
public:
	CThreadBase(void);
	virtual ~CThreadBase(void);

public:
	// 开启线程
	void vStart();

	// 结束线程
	virtual void vStop();

	// 线程是否可运行
	virtual bool isCanRun();

	// 子类重写此函数用于接收线程逻辑
	virtual int circle();

	// 入锁、解锁临界区,不同的编译环境修改成其他的同步条件即可
	void _lock();
	void _unLock();
	
protected:
	DWORD m_dThreadId;						// 线程ID	
	bool m_bCanRun;							// 是否可以运行
	int m_nThreadHandle;					// 线程句柄

#ifdef WINVER
	CRITICAL_SECTION m_criSection;		// 临界区,定义一个,需要数据同步的自取即可
#endif
};
// 源文件
#include "ThreadBase.h"
//#include <afxwin.h>

// 线程函数
DWORD WINAPI threadProc(LPVOID pArgs)
{
	if (0 == pArgs)
		return 0;

	CThreadBase* pThreadBase = (CThreadBase*)pArgs;
	pThreadBase->circle();
	return 0;
}

CThreadBase::CThreadBase(void)
{
	m_bCanRun = false;
	m_dThreadId = 0;
	m_nThreadHandle = NULL;

#ifdef WINVER
	InitializeCriticalSection(&m_criSection);
#endif
}

CThreadBase::~CThreadBase(void)
{
}

void CThreadBase::vStart()
{
	m_nThreadHandle = (int)CreateThread(NULL, 0, threadProc, this, 0, &m_dThreadId);
	m_bCanRun = true;
}

void CThreadBase::vStop()
{
	m_bCanRun = false;
}

bool CThreadBase::isCanRun()
{
	return m_bCanRun;
}

int CThreadBase::circle()
{
	return TRUE;
}

void CThreadBase::_lock()
{
#ifdef WINVER
	EnterCriticalSection(&m_criSection);
#endif
}

void CThreadBase::_unLock()
{
#ifdef WINVER
	LeaveCriticalSection(&m_criSection);
#endif
}

使用する場合:

(1) このクラスを直接継承すると、サブクラスはスレッドのロジックを受け取るために使用されるcircle() 関数を書き換えることができます。

(2) スレッドに実行させたい関数は、サブクラスのcircle()内に記述できます。

おすすめ

転載: blog.csdn.net/bigger_belief/article/details/131698473