当前位置: 首页 > news >正文

线程同步

在windows上,线程之间的同步有很多种方式,以下是利用事件对象实现同步的例子

#include <iostream>
#include <windows.h>
using namespace std;

HANDLE g_hEvent = NULL;

//
DWORD WINAPI ThreadProc1(LPVOID lpVoid)
{
	if (!g_hEvent)
	{
		return 1;
	}
	if (WAIT_OBJECT_0 == WaitForSingleObject(g_hEvent, INFINITE))
	{
		for (int i = 0; i < 20; i++)
		{
			cout << "1 ";
		}
		cout << endl;
		SetEvent(g_hEvent);
	}
	return 0;
}

//
DWORD WINAPI ThreadProc2(LPVOID lpVoid)
{
	if (!g_hEvent)
	{
		return 1;
	}
	if (WAIT_OBJECT_0 == WaitForSingleObject(g_hEvent, INFINITE))
	{
		for (int i = 0; i < 20; i++)
		{
			cout << "2 ";
		}
		cout << endl;
		SetEvent(g_hEvent);
	}
	return 0;
}

//
int main()
{
	HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, CREATE_SUSPENDED, NULL);
	if (!hThread1)
	{
		cerr << "CreateThread1 error: " << GetLastError() << endl;
		return 1;
	}
	HANDLE hThraed2 = CreateThread(NULL, 0, ThreadProc2, NULL, CREATE_SUSPENDED, NULL);
	if (!hThraed2)
	{
		cerr << "CreateThread2 error: " << GetLastError() << endl;
		return 1;
	}

	// 1、系统自动重置事件对象,这样,当g_hEvent为有信号时,只有一个线程能获得该对象,
	// WaitForSingleObject函数得到执行允许时,会自动将g_hEvent设置为非信号状态
	// 2、如果是人工重置的事件对象,当g_hEvent为有信号时,所有线程都能够同时执行(这就不能达到线程间同步啦)
	// WaitForSingleObject函数得到执行允许时,不会将事件对象设置为非信号状态,如果此时调用SetEvent,
	// 可能时间片已终止,线程切换,SetEvent等于没作用

	g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);	// 创建系统自动重置对象
	if (!g_hEvent)
	{
		cerr << "CreateEvent: " << GetLastError() << endl;
		return 1;
	}

	ResumeThread(hThread1);
	ResumeThread(hThraed2);
	
	SetEvent(g_hEvent);
	if (WAIT_OBJECT_0 == WaitForSingleObject(g_hEvent, INFINITE))
	{
		for (int  i = 0; i < 20; i++)
		{
			cout << "3 ";
		}
		cout << endl;
		SetEvent(g_hEvent);
	}

	CloseHandle(hThread1);
	CloseHandle(hThraed2);

	Sleep(10);		// 让另外两个线程有时间执行完毕

	CloseHandle(g_hEvent);

	system("pause");
	return 0;
}

事件对象不但可以做到线程间的同步,还可以做到进程间的同步,因为它是内核级的对象,是所有进程所共享的。


在linux上,线程之间的同步也是多种方式的,以下是利用互斥量实现同步的例子:

#include <iostream>
#include <pthread.h>
using namespace std;

pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;    // 定义一个互斥量

void *ThreadProc1(void *pVoid)
{
    pthread_mutex_lock(&g_mutex);
    for (int i = 0; i < 20; i++)
    {
        cout << "1 ";
    }
    cout << endl;
    pthread_mutex_unlock(&g_mutex);
}

void *ThreadProc2(void *pVoid)
{
    pthread_mutex_lock(&g_mutex);
    for (int i = 0; i < 20; i++)
    {
        cout << "2 ";
    }
    cout << endl;
    pthread_mutex_unlock(&g_mutex);
}

int main()
{
    pthread_t nTid1 = 0;
    int nErr1 = pthread_create(&nTid1, NULL, ThreadProc1, NULL);
    if (nErr1 != 0)
    {
        cerr << "thread1 create error: " << nErr1 << endl;
        return 1;
    }

    pthread_t nTid2 = 0;
    int nErr2 = pthread_create(&nTid2, NULL, ThreadProc2, NULL);
    if (nErr2 != 0)
    {
        cerr << "thread2 create error: " << nErr2 << endl;
        return 1;
    }

    pthread_mutex_lock(&g_mutex);
    for (int i = 0; i < 20; i++)
    {
        cout << "3 ";
    }
    cout << endl;
    pthread_mutex_unlock(&g_mutex);
    sleep(1);
    pthread_mutex_destroy(&g_mutex);

    return 0;
}

可能有的朋友在执行上面的代码时发现,即使把互斥量去掉,程序也能正确的输出,是的,有可能,因为我们的执行时间比较短,线程的时间片足以支撑该线程进行输出操作,那么,上面的代码是否真正同步呢,有兴趣的朋友可以在每个输出的地方加个usleep(1)试下,就可以发现,确实是已经同步了哈。


顺便来看看python实现线程同步的方式,python实现同步的方式是lock,每次只有一个线程能得到这个锁,当一个线程释放的时候,其他线程会有一个能获得该锁,而不能获得的线程将继续等待。

import threading
from time import sleep

def Thread1():
    lock.acquire()
    for i in range(1, 20):
        sleep(0.1)
        print("1 ", end = '')
    lock.release()

def Thread2():
    lock.acquire()
    for i in range(1, 20):
        sleep(0.1)
        print("2 ", end = '')
    lock.release()
    
if __name__ == "__main__":
    thread1 = threading.Thread(target = Thread1)
    thread2 = threading.Thread(target = Thread2)
    lock = threading.Lock()
    thread1.start()
    thread2.start()
    lock.acquire()
    for i in range(1, 20):
        sleep(0.1)
        print("3 ", end = '')
    lock.release()
    thread1.join()
    thread2.join()


相关文章:

  • AndEngine安全移除精灵的方式
  • 可评审代码之道
  • JDK的动态代理
  • 实验一 Linux基本环境
  • 病毒原理实例
  • 利用jodconverter+openoffice+flexpaper实现的在线文档系统核心demo
  • 八数码编码(优化数据结构,优化算法)
  • mac 下 git svn 设置代理
  • 实时机票/火车票抓取系统整体架构
  • 我是伪程序员
  • asp.net实验一:hello world!
  • asp.net实验二:连接sql server 2008数据库
  • ASP.NET实验三:读取web.config连接数据库
  • 谷歌面试题(持续更新)
  • web前端实验一:利用Js捕获鼠标事件实现图片切换
  • JavaScript 如何正确处理 Unicode 编码问题!
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • Angular2开发踩坑系列-生产环境编译
  • Cumulo 的 ClojureScript 模块已经成型
  • HTML中设置input等文本框为不可操作
  • JavaScript-Array类型
  • laravel with 查询列表限制条数
  • node和express搭建代理服务器(源码)
  • WePY 在小程序性能调优上做出的探究
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 聊聊directory traversal attack
  • 码农张的Bug人生 - 见面之礼
  • 目录与文件属性:编写ls
  • 前端相关框架总和
  • 一道面试题引发的“血案”
  • No resource identifier found for attribute,RxJava之zip操作符
  • 翻译 | The Principles of OOD 面向对象设计原则
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​LeetCode解法汇总518. 零钱兑换 II
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #1015 : KMP算法
  • #FPGA(基础知识)
  • (02)Hive SQL编译成MapReduce任务的过程
  • (a /b)*c的值
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (二十四)Flask之flask-session组件
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (篇九)MySQL常用内置函数
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (十六)串口UART
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)
  • .NET CF命令行调试器MDbg入门(四) Attaching to Processes
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .Net的DataSet直接与SQL2005交互
  • .pings勒索病毒的威胁:如何应对.pings勒索病毒的突袭?
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?