Liny_@NotePad

沉迷ACG中

【20090916】C++培训日记-多线程

YOYO posted @ 2009年9月16日 19:44 in 【C/C++】 with tags 多线程 , 2081 阅读

= = 老师讲了创建多线程、利用互斥信号、利用事件对象、利用临界区和杀死线程的方法。以下是demo……

【多线程样例】

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 多线程样例
//////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadFun(LPVOID lpParameter);

void main(void)
{
	HANDLE hThread1 = CreateThread(NULL, 0, ThreadFun, new int(1), 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, ThreadFun, new int(2), 0, NULL);
	HANDLE hThread3 = CreateThread(NULL, 0, ThreadFun, new int(3), 0, NULL);

	CloseHandle(hThread1);
	CloseHandle(hThread2);
	CloseHandle(hThread3);

	Sleep(3000);

	return;
}

DWORD WINAPI ThreadFun(LPVOID lpParameter)
{
	while (true)
	{
		printf("Thread %d is running..\n", *((int*)lpParameter));
		Sleep(50);
	}
}

【多线程:出现同步问题样例】

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 多线程出错样例 演示
//////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI SellTickets(LPVOID lpParameter);

int		g_nTicket = 100;

void main(void)
{
	HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(2), 0, NULL);

	CloseHandle(hThread1);
	CloseHandle(hThread2);

	Sleep(3000);

	system("pause");

	return;
}

DWORD WINAPI SellTickets(LPVOID lpParameter)
{
	while (g_nTicket > 0)
	{
		printf("Thread %d sells ticket: No.%d\n", *((int*)lpParameter), g_nTicket--);
	}

	return NULL;
}

【使用互斥信号量:线程结束时会自动释放占用的信号量】

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 线程结束时会自动释放互斥量 演示
//////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadFun(LPVOID lpParameter);

HANDLE	g_hMutex;

void main(void)
{
	g_hMutex = CreateMutex(NULL, FALSE, NULL);

	HANDLE hThread1 = CreateThread(NULL, 0, ThreadFun, new int(1), 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, ThreadFun, new int(2), 0, NULL);
	HANDLE hThread3 = CreateThread(NULL, 0, ThreadFun, new int(3), 0, NULL);

	CloseHandle(hThread1);
	CloseHandle(hThread2);
	CloseHandle(hThread3);

	CloseHandle(g_hMutex);

	system("pause");
}

DWORD WINAPI ThreadFun(LPVOID lpParameter)
{
	WaitForSingleObject(g_hMutex, INFINITE);
	printf("Thread %d is running..\n", *((int*)lpParameter));
	return NULL;
}

【使用互斥信号量解决同步问题(手动申请与释放互斥量)】

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 线程手动申请释放互斥量 演示
//////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI SellTickets(LPVOID lpParameter);

int		g_nTickets = 100;
HANDLE	g_hMutex;

void main(void)
{
	g_hMutex = CreateMutex(NULL, FALSE, NULL);

	HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL);
	HANDLE hThread3 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL);

	CloseHandle(hThread1);
	CloseHandle(hThread2);
	CloseHandle(hThread3);

	Sleep(1000);

	CloseHandle(g_hMutex);

	system("pause");

	return;
}

DWORD WINAPI SellTickets(LPVOID lpParameter)
{
	while (true)
	{
		WaitForSingleObject(g_hMutex, INFINITE);
		if (g_nTickets > 0)
		{
			printf("Thread %d sells ticket: No.%d\n", *((int*)lpParameter), g_nTickets--);
		}
		else
		{
			break;
		}
		ReleaseMutex(g_hMutex);
	}
	
	return NULL;
}

【使用事件对象:手动重置事件对象(仍然有出现同步问题的可能)】

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 手动重置事件对象
//////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI SellTickets(LPVOID lpParameter);

int		g_nTickets = 100;
HANDLE	g_hEvent;

void main(void)
{
	g_hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);

	HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(2), 0, NULL);
	HANDLE hThread3 = CreateThread(NULL, 0, SellTickets, new int(3), 0, NULL);

	CloseHandle(hThread1);
	CloseHandle(hThread2);
	CloseHandle(hThread3);

	CloseHandle(g_hEvent);

	system("pause");
	return;
}

DWORD WINAPI SellTickets(LPVOID lpParameter)
{
	while (true)
	{
		WaitForSingleObject(g_hEvent, INFINITE);
		ResetEvent(g_hEvent);

		if (g_nTickets > 0)
		{
			printf("Thread %d sells tickets: %d\n", *((int*) lpParameter), g_nTickets--);
		}
		else
		{
			break;
		}

		SetEvent(g_hEvent);
	}

	return NULL;
}

【使用事件对象:自动重置】

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 自动重置事件对象 演示
//////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI SellTickets(LPVOID lpParameter);

int		g_nTickets = 100;
HANDLE	g_hEvent;

void main(void)
{
	g_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);

	HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(2), 0, NULL);
	HANDLE hThread3 = CreateThread(NULL, 0, SellTickets, new int(3), 0, NULL);

	CloseHandle(hThread1);
	CloseHandle(hThread2);
	CloseHandle(hThread3);

	Sleep(1000);

	CloseHandle(g_hEvent);

	system("pause");
	return;
}

DWORD WINAPI SellTickets(LPVOID lpParameter)
{
	while (true)
	{
		WaitForSingleObject(g_hEvent, INFINITE);

		if (g_nTickets > 0)
		{
			printf("Thread %d sells ticket: No.%d\n", *((int*) lpParameter), g_nTickets--);
		}
		else
		{
			break;
		}

		SetEvent(g_hEvent);
	}

	return NULL;
}

【使用临界区】

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 使用临界区实现同步 演示
//////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI SellTickets(LPVOID lpParameter);

int					g_nTickets = 100;
CRITICAL_SECTION	g_cs;

void main(void)
{
	InitializeCriticalSection(&g_cs);

	HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(2), 0, NULL);
	HANDLE hThread3 = CreateThread(NULL, 0, SellTickets, new int(3), 0, NULL);

	CloseHandle(hThread1);
	CloseHandle(hThread2);
	CloseHandle(hThread3);

	Sleep(1000);

	DeleteCriticalSection(&g_cs);

	system("pause");
	return;
}

DWORD WINAPI SellTickets(LPVOID lpParameter)
{
	while (true)
	{
		EnterCriticalSection(&g_cs);

		if (g_nTickets > 0)
		{
			printf("Thread %d sells ticket: No.%d\n", *((int*)lpParameter), g_nTickets--);
		}
		else
		{
			break;
		}

		LeaveCriticalSection(&g_cs);
	}

	return NULL;
}

【使用临界区:死锁样例】

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 使用临界区造成死锁样例
//////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadFun1(LPVOID lpParameter);
DWORD WINAPI ThreadFun2(LPVOID lpParameter);

CRITICAL_SECTION	g_csA;
CRITICAL_SECTION	g_csB;

void main(void)
{
	InitializeCriticalSection(&g_csA);
	InitializeCriticalSection(&g_csB);

	HANDLE hThread1 = CreateThread(NULL, 0, ThreadFun1, NULL, 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, ThreadFun2, NULL, 0, NULL);

	CloseHandle(hThread1);
	CloseHandle(hThread2);

	Sleep(3000);

	DeleteCriticalSection(&g_csA);
	DeleteCriticalSection(&g_csB);

	system("pause");
	return;
}

DWORD WINAPI ThreadFun1(LPVOID lpParameter)
{
	while (true)
	{
		EnterCriticalSection(&g_csA);
		EnterCriticalSection(&g_csB);

		printf("Thread1 is running..\n");

		LeaveCriticalSection(&g_csB);
		LeaveCriticalSection(&g_csA);
	}

	return NULL;
}

DWORD WINAPI ThreadFun2(LPVOID lpParameter)
{
	while (true)
	{
		EnterCriticalSection(&g_csB);
		EnterCriticalSection(&g_csA);

		printf("Thread2 is running..\n");

		LeaveCriticalSection(&g_csA);
		LeaveCriticalSection(&g_csB);
	}

	return NULL;
}

【封装的临界区类】

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 封装的临界区类
//////////////////////////////////////////////////////////////////////////
#ifndef _MULTITHREAD_CRITICALLOCK_H_
#define _MULTITHREAD_CRITICALLOCK_H_

#if _MSC_VER > 1000
#pragma once
#endif

#include <Windows.h>

class CCriticallLock
{
public:
	CCriticallLock(void);
	~CCriticallLock(void);

public:
	void Lock(void);
	void Unlock(void);

private:
	CRITICAL_SECTION	m_objCriticalSection;
};

#endif	//	end of define _MULTITHREAD_CRITICALLOCK_H_
//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 封装的临界区类
//////////////////////////////////////////////////////////////////////////
#include "CriticallLock.h"

CCriticallLock::CCriticallLock(void)
{
	InitializeCriticalSection(&m_objCriticalSection);
}

CCriticallLock::~CCriticallLock(void)
{
	DeleteCriticalSection(&m_objCriticalSection);
}

void CCriticallLock::Lock()
{
	EnterCriticalSection(&m_objCriticalSection);
}

void CCriticallLock::Unlock()
{
	LeaveCriticalSection(&m_objCriticalSection);
}

 

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 封装的临界区类 使用
//////////////////////////////////////////////////////////////////////////
#include "CriticallLock.h"
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI SellTickets(LPVOID lpParameter);

int				g_nTickets = 100;
CCriticallLock	g_objCriticallLock;

void main(void)
{
	HANDLE hThread1 = CreateThread(NULL, 0, SellTickets, new int(1), 0, NULL);
	HANDLE hThread2 = CreateThread(NULL, 0, SellTickets, new int(2), 0, NULL);
	HANDLE hThread3 = CreateThread(NULL, 0, SellTickets, new int(3), 0, NULL);

	CloseHandle(hThread1);
	CloseHandle(hThread2);
	CloseHandle(hThread3);

	Sleep(1000);

	system("pause");
	return;
}

DWORD WINAPI SellTickets(LPVOID lpParameter)
{
	while (true)
	{
		g_objCriticallLock.Lock();

		if (g_nTickets > 0)
		{
			printf("Thread %d sells ticket: No.%d\n", *((int*)lpParameter), g_nTickets--);
		}
		else
		{
			break;
		}

		g_objCriticallLock.Unlock();
	}

	return NULL;
}

【杀死主线程】需要使用DuplicateHandle来获得当前线程的HANDLE,否则不能成功删除主线程。删除后执行TerminateThread的子线程篡位成为主线程。

//////////////////////////////////////////////////////////////////////////
//	CopyRight(c) 2009, YOYO, All Rights Reserved.
//	Author: LIN YiQian
//	Created: 2009/09/16
//	Describe: 子线程杀死主线程 演示
//////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadFun(LPVOID lpParameter);

void main(void)
{
	HANDLE hMainThread;

	DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), 
		&hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS);

	HANDLE hThread = CreateThread(NULL, 0, ThreadFun, &hMainThread, 0, NULL);

	while (true)
	{
		printf("主线程运行中 - -..\n");
		Sleep(100);
	}

	CloseHandle(hThread);

	return;
}

DWORD WINAPI ThreadFun(LPVOID lpParameter)
{
	HANDLE hMainThread = *((HANDLE*) lpParameter);
	TerminateThread(hMainThread, 0);

	while (true)
	{
		printf("子线程运行中。。\n");
		Sleep(100);
	}
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter