,,C++ 如何实现多线程与线程同步

,,C++ 如何实现多线程与线程同步

多线程中的线程同步可以使用,创建线程,创建互斥体互斥锁实现线程同步,通过临界区实现线程同步,旗语基于信号实现线程同步,创建事件事件对象的同步,以及线程函数传递单一参数与多个参数的实现方式。

目录

创建线程实现多线程:beginthreadex实现多线程:创建互斥体互斥锁实现线程同步:通过临界区实现线程同步:信号量基于信号实现线程同步:CreateEvent事件对象的同步:线程函数传递单个参数:线程函数传递多参数:

CreateThread 实现多线程:

先来创建一个简单的多线程实例,无参数传递版,运行实例会发现,主线程与子线程运行无规律。

#包含windows.h

#包括输入输出流

使用命名空间标准

DWORD WINAPI函数(LPVOID lpParamter)

{

for(int x=0;x 10x)

{

cout "线程函数“恩德尔

睡眠(200);

}

返回0;

}

int main(int argc,char * argv[])

{

HANDLE hThread=CreateThread(NULL,0,Func,NULL,0,NULL);

关闭手柄(hThread);

for(int x=0;x 10x)

{

cout "主线程“恩德尔

睡眠(400);

}

系统("暂停");

返回0;

}

beginthreadex 实现多线程:

这个方法与前面的创建线程使用完全一致,只是在参数上面应使用无效*该参数可以强转为任意类型,两者实现效果完全一致。

#包含windows.h

#包括输入输出流

#包含流程。h

使用命名空间标准

无符号WINAPI函数(void *arg)

{

for(int x=0;x 10x)

{

cout "线程函数“恩德尔

睡眠(200);

}

返回0;

}

int main(int argc,char * argv[])

{

HANDLE hThread=(HANDLE)_ beginthreadex(NULL,0,Func,NULL,0,NULL);

关闭手柄(hThread);

for(int x=0;x 10x)

{

cout "主线程“恩德尔

睡眠(400);

}

系统("暂停");

返回0;

}

CreateMutex 互斥锁实现线程同步:

使用互斥锁可以实现单位时间内,只允许一个线程拥有对共享资源的独占,从而实现了互不冲突的线程同步。

#包含windows.h

#包括输入输出流

使用命名空间标准

HANDLE hMutex=NULL//创建互斥锁

//线程函数

DWORD WINAPI函数(LPVOID lpParamter)

{

for(int x=0;x 10x)

{

//请求获得一个互斥锁

WaitForSingleObject(hMutex,INFINITE);

cout ' thread func ' endl

//释放互斥锁

释放互斥体(hMutex);

}

返回0;

}

int main(int argc,char * argv[])

{

HANDLE hThread=CreateThread(NULL,0,Func,NULL,0,NULL);

hMutex=CreateMutex(NULL,FALSE,' ly shark ');

关闭手柄(hThread);

for(int x=0;x 10x)

{

//请求获得一个互斥锁

WaitForSingleObject(hMutex,INFINITE);

cout "主线程“恩德尔

//释放互斥锁

释放互斥体(hMutex);

}

系统("暂停");

返回0;

}

通过互斥锁,同步执行两个线程函数。

#包含windows.h

#包括输入输出流

使用命名空间标准

HANDLE hMutex=NULL//创建互斥锁

#定义数量_线程50

//线程函数一

DWORD WINAPI FuncA(LPVOID LP parameter)

{

for(int x=0;x 10x)

{

//请求获得一个互斥锁

WaitForSingleObject(hMutex,INFINITE);

cout '这是线程func A ' endl

//释放互斥锁

释放互斥体(hMutex);

}

返回0;

}

//线程函数2

DWORD WINAPI FuncB(LPVOID LP parameter)

{

for(int x=0;x 10x)

{

//请求获得一个互斥锁

WaitForSingleObject(hMutex,INFINITE);

cout '这是线程func B ' endl

//释放互斥锁

释放互斥体(hMutex);

}

返回0;

}

int main(int argc,char * argv[])

{

//用来存储线程函数的句柄

HANDLE thand le[NUM _ THREAD];

///创建互斥量,此时为表示状态

hMutex=CreateMutex(NULL,FALSE,' ly shark ');

for(int x=0;x数量_线程;x)

{

如果(x % 2)

{

tHandle[x]=CreateThread(NULL,0,FuncA,NULL,0,NULL);

}

其他

{

tHandle[x]=CreateThread(NULL,0,FuncB,NULL,0,NULL);

}

}

//等待所有线程函数执行完毕

WaitForMultipleObjects(NUM _ THREAD,tHandle,TRUE,INFINITE);

//销毁互斥对象

关闭手柄(hMutex);

系统("暂停");

返回0;

}

通过临界区实现线程同步:

临界区与互斥锁差不多,临界区使用时会创建关键部分临界区对象,同样相当于一把钥匙,线程函数执行结束自动上交,如下是临界区函数的定义原型。

//初始化函数原型

VOID InitializeCriticalSection(

LP临界段

);

//销毁函数原型

VOID DeleteCriticalSection(

LP临界段

);

//获取

VOID EnterCriticalSection(

LP临界段

);

//释放

VOID LeaveCriticalSection(

LP临界段

);

这一次我们不适用互斥体,使用临界区实现线程同步,结果与互斥体完全一致,看个人喜好。

#包含windows.h

#包括输入输出流

使用命名空间标准

临界_截面cs;//全局定义临界区对象

#定义数量_线程50

//线程函数

DWORD WINAPI FuncA(LPVOID LP parameter)

{

for(int x=0;x 10x)

{

//进入临界区

进入临界区(cs);

cout '这是线程func A ' endl

//离开临界区

LeaveCriticalSection(cs);

}

返回0;

}

int main(int argc,char * argv[])

{

//用来存储线程函数的句柄

HANDLE thand le[NUM _ THREAD];

//初始化临界区

InitializeCriticalSection(cs);

for(int x=0;x数量_线程;x)

{

tHandle[x]=CreateThread(NULL,0,FuncA,NULL,0,NULL);

}

//等待所有线程函数执行完毕

WaitForMultipleObjects(NUM _ THREAD,tHandle,TRUE,INFINITE);

//释放临界区

DeleteCriticalSection(cs);

系统("暂停");

返回0;

}

Semaphore 基于信号实现线程同步:

通过定义一个信号,初始化信号为0,利用信号量值为0时进入无信号的状态,大于0时进入表示状态的特性即可实现线程同步。

#包含windows.h

#包括输入输出流

使用命名空间标准

静态句柄信号量;

静态句柄信号量二;

//线程函数一

DWORD WINAPI FuncA(LPVOID LP parameter)

{

for(int x=0;x 10x)

{

//临界区开始时设置表示状态

WaitForSingleObject(SemaphoreOne,INFINITE);

cout '这是线程func A ' endl

//临界区结束则设置为无信号的状态

ReleaseSemaphore(SemaphoreOne,1,NULL);

}

返回0;

}

//线程函数2

DWORD WINAPI FuncB(LPVOID LP parameter)

{

for(int x=0;x 10x)

{

//临界区开始时设置表示状态

WaitForSingleObject(信号量二,无限);

cout '这是线程func B ' endl

//临界区结束则设置为无信号的状态

ReleaseSemaphore(SemaphoreTwo,1,NULL);

}

返回0;

}

int main(int argc,char * argv[])

{

//用来存储线程函数的句柄

处理hThreadA,hThreadB

//创建信号量对象,并且设置为0进入无信号的状态

semaphore one=创建信号量(NULL,0,1,NULL);

//创建信号量对象,并且设置为一进入表示状态

信号量二=创建信号量(NULL,1,1,NULL);//先执行这一个线程函数

hThreadA=CreateThread(NULL,0,FuncA,NULL,0,NULL);

hThreadB=CreateThread(NULL,0,FuncB,NULL,0,NULL);

//等待两个线程函数执行完毕

WaitForSingleObject(hThreadA,INFINITE);

WaitForSingleObject(hThreadA,INFINITE);

//销毁两个线程函数

关闭句柄(SemaphoreOne);

关闭句柄(信号量二);

系统("暂停");

返回0;

}

上面的一段代码,容易产生死锁现象,即,线程函数B执行完成后,一个函数一直处于等待状态。

执行WaitForSingleObject(semTwo,INFINITE);会让线程函数进入类似挂起的状态,当接到ReleaseSemaphore(semOne,1,NULL);才会恢复执行。

#包含windows.h

#包含标准视频

静态句柄塞蒙,塞蒙二

静态整数;

//线程函数A用于接收参书

DWORD WINAPI读取号(LPVOID lpparameter)

{

int I;

for(I=0;i5;我)

{

fputs('输入号: ',stdout);

//临界区的开始表示状态

WaitForSingleObject(semTwo,INFINITE);

scanf('%d ',编号);

//临界区的结束无信号的状态

ReleaseSemaphore(semOne,1,NULL);

}

返回0;

}

//线程函数乙:用户接受参数后完成计算

DWORD WINAPI检查(LPVOID lpParamter)

{

int sum=0,I;

for(I=0;i5;我)

{

//临界区的开始无信号的状态

WaitForSingleObject(semOne,INFINITE);

总和=数量

//临界区的结束表示状态

ReleaseSemaphore(semTwo,1,NULL);

}

printf('数字为:%d \n ',sum);

返回0;

}

int main(int argc,char *argv[])

{

处理高温线程1、高温线程2

//创建信号量对象,设置为0进入无信号的状态

semOne=CreateSemaphore(NULL,0,1,NULL);

//创建信号量对象,设置为一进入表示状态

semTwo=CreateSemaphore(NULL,1,1,NULL);

hThread1=CreateThread(NULL,0,ReadNumber,NULL,0,NULL);

hThread2=CreateThread(NULL,0,Check,NULL,0,NULL);

//关闭临界区

WaitForSingleObject(hThread1,INFINITE);

WaitForSingleObject(hThread2,INFINITE);

关闭手柄(se mone);

关闭手柄(SEM两个);

系统("暂停");

返回0;

}

CreateEvent 事件对象的同步:

事件对象实现线程同步,与前面的临界区和互斥体有很大的不同,该方法下创建对象时,可以在自动无信号的状态运行的自动复位模式,当我们设置好我们需要的参数时,可以直接使用设置事件(赫文特)设置事件状态,会自动执行线程函数。

#包含windows.h

#包含标准视频

#包含流程。h

#定义字符串长度100

//存储全局字符串

静态字符字符串[STR _ LEN];

//设置事件句柄

静态手柄事件;

//统计字符串中是否存在A

无符号WINAPI NumberOfA(void *arg)

{

int CNT=0;

//等待线程对象事件

WaitForSingleObject(hEvent,INFINITE);

for(int I=0;str[i]!=0;我)

{

if (str[i]=='A ')

(cannot)不能

}

printf(' A的数量:%d \n ',CNT);

返回0;

}

//统计字符串总长度

无符号WINAPI NumberOfOthers(void *arg)

{

int CNT=0;

//等待线程对象事件

WaitForSingleObject(hEvent,INFINITE);

for(int I=0;str[i]!=0;我)

{

if (str[i]!='A ')

(cannot)不能

}

printf('其他数量:%d \n ',CNT-1);

返回0;

}

int main(int argc,char *argv[])

{

处理高温线程1、高温线程2

//以无信号的创建手动复位模式的事件对象

//该对象创建后不会被立即执行,只有我们设置状态为表示时才会继续

hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);

hthread 1=(HANDLE)_ beginthreadex(NULL,0,NumberOfA,NULL,0,NULL);

hthread 2=(HANDLE)_ beginthreadex(NULL,0,NumberOfOthers,NULL,0,NULL);

fputs('输入字符串: ',stdout);

fgets(str,STR_LEN,stdin);

//字符串读入完毕后,将事件句柄改为表示状态

SetEvent(何发泄);

WaitForSingleObject(hThread1,INFINITE);

WaitForSingleObject(hThread2,INFINITE);

//无信号如果不更改,对象继续停留在表示

复位事件(he发泄);

关闭手柄(he排气孔);

系统("暂停");

返回0;

}

线程函数传递单个参数:

线程函数中的定义中LPVOID允许传递一个参数,只需要在县城函数中接收并强转(int)(LPVOID)端口即可。

#包含标准视频

#包含Windows.h

//线程函数接收一个参数

DWORD WINAPI扫描线程(LPVOID端口)

{

//将参数强制转化为需要的类型

int Port=(int)(LPVOID)Port;

printf('[ ]端口:] \n ',端口);

返回1;

}

int main(int argc,char* argv[])

{

手柄把手;

for(int port=0;端口100;端口)

{

handle=CreateThread(NULL,0,(LPTHREAD _ START _ ROUTINE)ScanThread,(LPVOID)port,0,0);

}

WaitForSingleObject(句柄,无限);

系统("暂停");

返回0;

}

线程函数传递多参数:

如果想在线程函数中传递多个参数,则需要传递一个结构指针,通过线程函数内部强转为结构类型后,取值,这个案例花费了我一些时间,网上也没找到合适的解决方法,或找到的都是歪瓜裂枣瞎转的东西,最后还是自己研究了一下写了一个没为题的。

其主要是线程函数中调用的参数会与下一个线程函数结构相冲突,解决的办法时在每次进入线程函数时,自己拷贝一份,每个人使用自己的那一份,才可以避免此类事件的发生,同时最好配合线程同步一起使用,如下时线程扫描器的部分代码片段。

#包含标准视频

#包含windows.h

typedef结构_线程_参数

{

char * HostAddr//扫描主机

DWORD dwStartPort//端口号

}线程_参数

//这个扫描线程函数

DWORD WINAPI扫描线程(LPVOID lpParam)

{

//拷贝传递来的扫描参数

THREAD _ PARAM扫描参数={ 0 };

//这一步很重要,如不拷贝,则会发生重复赋值现象,导致扫描端口一直都是一个。

//坑死人的玩意,一开始我始终没有发现这个问题某人玩意!

MoveMemory(ScanParam,lpParam,sizeof(THREAD _ PARAM));

printf('地址:%-16s -端口:%-5d状态:[Open] \n ',ScanParam .扫描参数。dw起始端口);

返回0;

}

int main(int argc,char *argv[])

{

THREAD _ PARAM线程参数={ 0 };

ThreadParam .HostAddr=' 192。168 .1 .10 ';

对于(双字端口=1;端口100;端口)

{

螺纹参数。dw起始端口=端口;

HANDLE hThread=CreateThread(NULL,0,ScanThread,(LPVOID)ThreadParam,0,NULL);

WaitForSingleObject(hThread,INFINITE);

}

系统("暂停");

返回0;

}

文章出处:https://www.cnblogs.com/lyshark

以上就是C如何实现多线程与线程同步的详细内容,更多关于C实现多线程与线程同步的资料请关注我们其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • vs2015打包安装程序,vs2015程序打包,VS2022实现VC++打包生成安装文件图文详细历程
  • vc++6.0的快捷键,vc 快捷键
  • vc++6.0的快捷键,vc 快捷键,VC6.0常用快捷键大全
  • 绘制圆角矩形的方法,c++ 画矩形,C#画圆角矩形的方法
  • 懒汉式和饿汉式代码,单列模式懒汉和饿汉,C++单例模式的懒汉模式和饿汉模式详解
  • 好用的C++编译器,c++编译软件哪个好
  • semaphore c#,c++ semaphore
  • semaphore c#,c++ semaphore,C++中Semaphore内核对象用法实例
  • dev-c++使用教程,dev c++安装教程
  • dev-c++使用教程,dev c++安装教程,Dev C++ 安装及使用方法(图文教程)
  • C里面指针常量和常量指针的区别,c++指针常量和常量指针
  • C里面指针常量和常量指针的区别,c++指针常量和常量指针,简单总结C++中指针常量与常量指针的区别
  • com组件初始化失败,c#开发com组件,C++中COM组件初始化方法实例分析
  • c++静态成员变量使用,c++静态成员函数和静态成员变量
  • c++静态成员变量使用,c++静态成员函数和静态成员变量,详解c++ 静态成员变量
  • 留言与评论(共有 条评论)
       
    验证码: