多线程中的线程同步可以使用,创建线程,创建互斥体互斥锁实现线程同步,通过临界区实现线程同步,旗语基于信号实现线程同步,创建事件事件对象的同步,以及线程函数传递单一参数与多个参数的实现方式。
目录
创建线程实现多线程: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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。