IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> c++代码如何实现在win/linux下跨线程间事务触发实现(含示例代码) -> 正文阅读

[系统运维]c++代码如何实现在win/linux下跨线程间事务触发实现(含示例代码)

一、c++跨线程间的“击鼓传花”-事务触发

??????? 线程间事务机制本质上就是线程操作共享资源,最简单的实现,例如利用一个全局变量+全局互斥锁,各个线程就可以简单实现相互消息传递。
在实际应用中,引入事件对象,本质就是将这些共享资源包装成一个事件对象,在调用的过程中,所有线程都可以在一个等待函数中指定事件对象句柄。当指定的事务对象的状态被置为有信号状态时,事务对象等待函数将返回,线程将获得通知而被触发。

????????在win下,Windows API函数CreateEvent、WaitForSingleObject、SetEvent、ResetEvent、CloseHandle等实现事件对象的创建、设置、取值、重设、删除等操作,其内部使用了线程锁进行对象管理,实现跨线程事务相互调用。

??????? 在 linux下,没有提供现成API函数调用,但基于类似实现原理,采用线程互斥锁对象(ptread_mutex_t),通过其相关的pthread_mutex_init、pthread_mutex_lock、pthread_mutex_unlock、pthread_cond_wait、pthread_mutex_destroy等配套函数,实现实现跨线程间事务相互调用。

二、线程事务对象c++代码设计

??????? 工程项目如下,测试层逻辑简单设计,创建一个event_handle,将其传递给线程对象,并进行事件等待命令,在主线程进行命令输入来触发事件信号,线程对象获得事件返回来执行后续操作。

event_test
    bin
    build_win
    build_linux
    src
        event.h
        event.cpp
        myThread.h
        myThread.cpp
        win32Thread.h
        win32Thread.cpp
        testThread.h
        testThrad.cpp
        main.cpp
    CMakeLists.txt

event.h:

#ifndef _HIK_EVENT_H_
#define _HIK_EVENT_H_

#ifdef WIN32
#include <Windows.h>
#define event_handle HANDLE
#else
#include <pthread.h>

typedef struct
{
    bool state;
    bool manual_reset;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}event_t;
#define event_handle event_t*
#endif

//返回值:NULL 出错
event_handle event_create(bool manual_reset, bool init_state);

//返回值:0 等到事件,-1出错,句柄必须被触发信号后,函数才会返回
int event_wait(event_handle hevent);

//返回值:0 等到事件,1 超时,-1出错,建议比event_wait优先使用
int event_timedwait(event_handle hevent, long milliseconds);

//返回值:0 成功,-1出错
int event_set(event_handle hevent);

//返回值:0 成功,-1出错
int event_reset(event_handle hevent);

//返回值:无
void event_destroy(event_handle hevent);

#endif

event.cpp

#include "event.h"
#ifdef __linux
#include <sys/time.h>
#include <errno.h>
#endif
#include <iostream>
event_handle event_create(bool manual_reset, bool init_state)
{
#ifdef WIN32
    HANDLE hevent = CreateEvent(NULL, manual_reset, init_state, NULL);
#else
    event_handle hevent = new(std::nothrow) event_t;
    if (hevent == NULL)
    {
        return NULL;
    }
    hevent->state = init_state;
    hevent->manual_reset = manual_reset;
    if (pthread_mutex_init(&hevent->mutex, NULL))
    {
        delete hevent;
        return NULL;
    }
    if (pthread_cond_init(&hevent->cond, NULL))
    {
        pthread_mutex_destroy(&hevent->mutex);
        delete hevent;
        return NULL;
    }
#endif
    return hevent;
}
int event_wait(event_handle hevent)
{
#ifdef WIN32
    DWORD ret = WaitForSingleObject(hevent, INFINITE);
    if (ret == WAIT_OBJECT_0)
    {
        return 0;
    }
    return -1;
#else
    if (pthread_mutex_lock(&hevent->mutex))
    {
        return -1;
    }
    while (!hevent->state)
    {
        if (pthread_cond_wait(&hevent->cond, &hevent->mutex))
        {
            pthread_mutex_unlock(&hevent->mutex);
            return -1;
        }
    }
    if (!hevent->manual_reset)
    {
        hevent->state = false;
    }
    if (pthread_mutex_unlock(&hevent->mutex))
    {
		return -1;
	}
	return 0;
#endif
}
int event_timedwait(event_handle hevent, long milliseconds)
{
#ifdef WIN32
	DWORD ret = WaitForSingleObject(hevent, milliseconds);
	if (ret == WAIT_OBJECT_0)
	{
		return 0;
	}
	if (ret == WAIT_TIMEOUT)
	{
		return 1;
	}
	return -1;
#else

	int rc = 0;
	struct timespec abstime;
	struct timeval tv;
	gettimeofday(&tv, NULL);
	abstime.tv_sec  = tv.tv_sec + milliseconds / 1000;
	abstime.tv_nsec = tv.tv_usec*1000 + (milliseconds % 1000)*1000000;
	if (abstime.tv_nsec >= 1000000000)
	{
		abstime.tv_nsec -= 1000000000;
		abstime.tv_sec++;
	}

	if (pthread_mutex_lock(&hevent->mutex) != 0)
	{
		return -1;
	}
	while (!hevent->state)
	{
		if ((rc = pthread_cond_timedwait(&hevent->cond, &hevent->mutex, &abstime)))
		{
			if (rc == ETIMEDOUT) break;
			pthread_mutex_unlock(&hevent->mutex);
			return -1;
		}
	}
	if (rc == 0 && !hevent->manual_reset)
	{
		hevent->state = false;
	}
	if (pthread_mutex_unlock(&hevent->mutex) != 0)
	{
		return -1;
	}
	if (rc == ETIMEDOUT)
	{
		//timeout return 1
		return 1;
	}
	//wait event success return 0
	return 0;
#endif
}
int event_set(event_handle hevent)
{
#ifdef WIN32
	return !SetEvent(hevent);
#else
	if (pthread_mutex_lock(&hevent->mutex) != 0)
	{
		return -1;
	}

	hevent->state = true;

	if (hevent->manual_reset)
	{
		if(pthread_cond_broadcast(&hevent->cond))
		{
			return -1;
		}
	}
	else
	{
		if(pthread_cond_signal(&hevent->cond))
		{
			return -1;
		}
	}

	if (pthread_mutex_unlock(&hevent->mutex) != 0)
	{
		return -1;
	}

	return 0;
#endif
}
int event_reset(event_handle hevent)
{
#ifdef WIN32
	//ResetEvent 返回非零表示成功
	if (ResetEvent(hevent))
	{
		return 0;
	}
	return -1;
#else
	if (pthread_mutex_lock(&hevent->mutex) != 0)
	{
		return -1;
	}

	hevent->state = false;

	if (pthread_mutex_unlock(&hevent->mutex) != 0)
	{
		return -1;
	}
	return 0;
#endif
}
void event_destroy(event_handle hevent)
{
	if(hevent){
#ifdef WIN32
		CloseHandle(hevent);
#else
		pthread_cond_destroy(&hevent->cond);
		pthread_mutex_destroy(&hevent->mutex);
		delete hevent;
#endif
	}
}

win32Thread.h,win下父线程类实现

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef WIN32THREAD_H
#define WIN32THREAD_H

#include <process.h>
#include <iostream>

typedef void *HANDLE;
class MyThread
{
public:
	MyThread();
	~MyThread();
	void start();
	virtual int Run();
	HANDLE getThread();
private:
	HANDLE hThread;
	static void agent(void *p);
};
#endif

win32Thread.cpp

#include "win32Thread.h"

#include <windows.h>

MyThread::MyThread()
{
}

MyThread::~MyThread()
{
	WaitForSingleObject(hThread, INFINITE);
}

void MyThread::start()
{
    hThread =(HANDLE)_beginthread(agent, 0, (void *)this);
}
int MyThread::Run()
{
	printf("Base Thread\n");
	return 0;
}
void MyThread::agent(void *p)
{
    MyThread *agt = (MyThread *)p;
    agt->Run();
}
HANDLE MyThread::getThread()
{
    return hThread;
}

myThread.h,Linux下父线程类实现

/*
 * add arg in linux system and compile: -lpthread
 */

#ifndef _MYTHREAD_H
#define _MYTHREAD_H
#include <pthread.h>
#include <unistd.h>

class MyThread
{
private:
    //current thread ID
    pthread_t tid;
    //thread status
    int threadStatus;
    //get manner pointer of execution 
    static void* run0(void* pVoid);
    //manner of execution inside
    void* run1();
public:
    //threadStatus-new create
    static const int THREAD_STATUS_NEW = 0;
    //threadStatus-running
    static const int THREAD_STATUS_RUNNING = 1;
    //threadStatus-end
    static const int THREAD_STATUS_EXIT = -1;
    // constructed function
    MyThread();
    ~MyThread();
    //the entity for thread running
    virtual int Run()=0;
    //start thread
    bool start();
    //gte thread ID
    pthread_t getThreadID();
    //get thread status
    int getState();
    //wait for thread end
    void join();
    //wait for thread end in limit time
    void join(unsigned long millisTime);
};

#endif /* _MYTHREAD_H */

myThread.cpp

#include "myThread.h"

#include <stdio.h>

void* MyThread::run0(void* pVoid)
{
    MyThread* p = (MyThread*) pVoid;
    p->run1();
    return p;
}

void* MyThread::run1()
{
    threadStatus = THREAD_STATUS_RUNNING;
    tid = pthread_self();
    Run();
    threadStatus = THREAD_STATUS_EXIT;
    tid = 0;
    pthread_exit(NULL);
}

MyThread::MyThread()
{
    tid = 0;
    threadStatus = THREAD_STATUS_NEW;
}

MyThread::~MyThread()
{
	join(10);
}

int MyThread::Run()
{
    while(true){
        printf("thread is running!\n");
        sleep(100);
    }
    return 0;
}

bool MyThread::start()
{
    return pthread_create(&tid, NULL, run0, this) == 0;
}

pthread_t MyThread::getThreadID()
{
    return tid;
}

int MyThread::getState()
{
    return threadStatus;
}

void MyThread::join()
{
    if (tid > 0)
    {
        pthread_join(tid, NULL);
    }
}

void MyThread::join(unsigned long millisTime)
{
    if (tid == 0)
    {
        return;
    }
    if (millisTime >0)
    {
        unsigned long k = 0;
        while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime)
        {
            usleep(100);
            k++;
        }
    }
	join();
}

testThread.h,基于自定义win父线程类或linux父线程类为基类,实现等待事件响应输出

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef TIME_UP_INFO_H
#define TIME_UP_INFO_H
/*
测试线程,测试事件类跨线程通信机制.
*/
#ifdef WIN32
#include "win32Thread.h"
#endif

#ifdef linux
#include "myThread.h"
#endif
#include "event.h"

class TestThread : public MyThread
{
public:
	TestThread(event_handle handle_);
	~TestThread();
	int Run();
private:
	bool running;
	event_handle handle_test;
};
#endif

testThread.cpp

#include "testThread.h"

#include <time.h>
#ifdef WIN32
#include <Windows.h>
#endif // WIN32
#ifdef linux
#include <stdio.h>
#endif

TestThread::TestThread(event_handle handle_) 
	: running(true)
	, handle_test(handle_)
{

};

TestThread::~TestThread()
{
	running = false;
};

int TestThread::Run()
{
	int i=0,j=0;
	while (running)
	{
		//超时等待及持续等待测试
		if(0==event_timedwait(handle_test,10000))
		//if(0==event_wait(handle_test))
		{
			printf("event_wait success %d \n",++i);
		}else{
			printf("event_wait failed %d \n",++j);
		}
#ifdef WIN32
		Sleep(10);
#else
		usleep(10000);
#endif
	}
	return 0;
};

main.cpp,创建一个事件对象,并传给测试线程类创建一个线程对象,在主线程捕获用户输入来触发事件设置,测试线程对象是否顺便获得事务通知,实现线程间消息传递。

#ifdef WIN32
#include <conio.h>
#endif
#ifdef linux
#include <stdio.h>
#endif

#include "event.h"
#include "testThread.h"

int main(int argc, char* argv[])
{
	event_handle handle_ = event_create(false,true);
	//event_handle handle_ = event_create(true,true);
	if(NULL==handle_)
	{
		printf("event_create failed!\n");
		return 0;
	}
	TestThread th(handle_);
	th.start();
	bool bExit = false;
	char ch = '0';
	int i=1, j=0;
	while(!bExit)
	{
		ch = getchar();
		switch(ch)
		{
			case 'q':
				bExit = true;
				break;
			case 'w':
				if(0==event_set(handle_))
					printf("event_set success %d \n",++i);
				break;
			case 's':
				if(0==event_reset(handle_))
					printf("event_reset success %d \n",++j);
				break;
			default:
				break;
		}
	}
	event_destroy(handle_);
	printf("test exit!");
	return 0;
}

三、代码编译及测试

win下采用cmake+vs2010,linux下采用cmake+gcc编译,CMakeLists.txt

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (event_test)
#
if(WIN32)
    message(STATUS "windows compiling...")
    add_definitions(-D_PLATFORM_IS_WINDOWS_)
	set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
	set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
	set(WIN_OS true)
else(WIN32)
    message(STATUS "linux compiling...")
    add_definitions( -D_PLATFORM_IS_LINUX_)
    add_definitions("-Wno-invalid-source-encoding")
	  # add_definitions("-O2")
    set(UNIX_OS true)
    set(_DEBUG true)
    
endif(WIN32)

#
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

# 指定源文件的目录,并将名称保存到变量
SET(source_h
    #
	${PROJECT_SOURCE_DIR}/src/event.h
	${PROJECT_SOURCE_DIR}/src/testThread.h
  )
  
SET(source_cpp
    #
	${PROJECT_SOURCE_DIR}/src/event.cpp
	${PROJECT_SOURCE_DIR}/src/testThread.cpp
	${PROJECT_SOURCE_DIR}/src/main.cpp
  )
  
#头文件目录
#include_directories(${PROJECT_SOURCE_DIR}/include)

if (${UNIX_OS})

SET(source_h_linux
	${PROJECT_SOURCE_DIR}/src/myThread.h
  )
  
SET(source_cpp_linux
  ${PROJECT_SOURCE_DIR}/src/myThread.cpp
)

add_definitions(
  "-W"
  "-fPIC"
  "-Wall"
  # "-Wall -g"
  "-Werror"
  "-Wshadow"
  "-Wformat"
  "-Wpointer-arith"
  "-D_REENTRANT"
  "-D_USE_FAST_MACRO"
  "-Wno-long-long"
  "-Wuninitialized"
  "-D_POSIX_PTHREAD_SEMANTICS"
  "-DACL_PREPARE_COMPILE"
  "-Wno-unused-parameter"
  "-fexceptions"
  )
  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")

link_directories()
# 指定生成目标
add_executable(event_test ${source_h} ${source_cpp}  ${source_h_linux} ${source_cpp_linux})
#link
target_link_libraries(event_test 
  -lpthread -pthread -lz -lrt -ldl
)

endif(${UNIX_OS})

if (${WIN_OS})

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819")

SET(source_h_win
	${PROJECT_SOURCE_DIR}/src/win32Thread.h
  )
  
SET(source_cpp_win
  ${PROJECT_SOURCE_DIR}/src/win32Thread.cpp
)

add_definitions(
  "-D_CRT_SECURE_NO_WARNINGS"
  "-D_WINSOCK_DEPRECATED_NO_WARNINGS"
  "-DNO_WARN_MBCS_MFC_DEPRECATION"
  "-DWIN32_LEAN_AND_MEAN"
)

link_directories()

if (CMAKE_BUILD_TYPE STREQUAL "Debug")

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/bin)
# 指定生成目标
add_executable(event_testd ${source_h} ${source_cpp} ${source_h_win} ${source_cpp_win})

else(CMAKE_BUILD_TYPE)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/bin)
# 指定生成目标
add_executable(event_test ${source_h} ${source_cpp} ${source_cpp_win})

endif (CMAKE_BUILD_TYPE)

endif(${WIN_OS})

编译命令如下

进入event_test目录
win:
mkdir build_win
cmake -G "Visual Studio 10 2010 Win64" -DCMAKE_BUILD_TYPE=Release ..
msbuild event_test.sln /p:Configuration="Release" /p:Platform="x64"
Linux:
mkdir build_linux
cmake ..
make

省略编译过程,以下是输出程序运行效果,左边是linux程序:

四、补充

完整的示例代码已经上传CSDN:

c++代码如何实现在win/linux下跨线程间事务触发实现完整示例代码-C++文档类资源-CSDN下载

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 02:22:56  更:2022-09-15 02:25:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 19:59:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计