一. 线程通信----事件:

  1.一对一模式:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> //互斥解决线程冲突
//事件解决线程通信
//临界区解决线程冲突
//时间同步线程 HANDLE event[] = { };
HANDLE hd[] = { }; DWORD WINAPI Zhang(void *p)
{
int i = ;
printf("张%d次说:I love you Li.\n", i);
Sleep();
SetEvent(event[]); while (++i)
{
WaitForSingleObject(event[], INFINITE); //无限等待一个信号
printf("张%d次说:I love you Li.\n", i);
Sleep();
//ResetEvent(event[0]); //信号复位
SetEvent(event[]);
} return ;
}
DWORD WINAPI Li(void *p)
{
int i = ;
while (++i)
{
WaitForSingleObject(event[], INFINITE); //无限等待一个信号
printf("李%d次说:I love you too.\n", i);
Sleep();
//ResetEvent(event[1]); //信号复位
SetEvent(event[]);
} return ;
} void main()
{
//第二个参数代表:自动FALSE、手动TRUE(需要reset)
//第三个参数信号状态
//第四个参数标记名称
//event[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
//event[1] = CreateEvent(NULL, TRUE, FALSE, NULL); event[] = CreateEvent(NULL, FALSE, FALSE, NULL);
event[] = CreateEvent(NULL, FALSE, FALSE, NULL); hd[] = CreateThread(NULL, , Zhang, NULL, , NULL);
hd[] = CreateThread(NULL, , Li, NULL, , NULL); WaitForMultipleObjects(, hd, TRUE, INFINITE); system("pause");
}

  2. 一对一中介者模式:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> //互斥解决线程冲突
//事件解决线程通信
//临界区解决线程冲突
//时间同步线程 HANDLE event[] = { };
HANDLE hd[] = { }; char str[] = { }; //全局变量,存放说的内容 DWORD WINAPI Wang(void *p)
{
int i = ;
int k = ; //判断是哪个信号 while (++i)
{
if (k == )
{
WaitForSingleObject(event[], INFINITE); //无限等待一个信号
printf("媒婆读取%d次:%s\n", i,str);
Sleep();
SetEvent(event[]); k = ;
}
else
{
WaitForSingleObject(event[], INFINITE); //无限等待一个信号
printf("媒婆读取%d次:%s\n", i, str);
Sleep();
SetEvent(event[]); k = ;
} } return ;
} DWORD WINAPI Zhang(void *p)
{
int i = ;
/*printf("张%d次说:I love you Li.\n", i);*/
memset(str, '', );
sprintf(str,"张%d次说:I love you Li.\n", i);
Sleep();
SetEvent(event[]); while (++i)
{
WaitForSingleObject(event[], INFINITE); //无限等待一个信号
/*printf("张%d次说:I love you Li.\n", i);*/
memset(str, '', );
sprintf(str,"张%d次说:I love you Li.\n", i);
Sleep();
//ResetEvent(event[0]); //信号复位
SetEvent(event[]);
} return ;
}
DWORD WINAPI Li(void *p)
{
int i = ;
while (++i)
{
WaitForSingleObject(event[], INFINITE); //无限等待一个信号
/*printf("李%d次说:I love you too.\n", i);*/
memset(str, '', );
sprintf(str,"李%d次说:I love you too.\n", i);
Sleep();
//ResetEvent(event[1]); //信号复位
SetEvent(event[]);
} return ;
} void main()
{
//第二个参数代表:自动FALSE、手动TRUE(需要reset)
//第三个参数信号状态
//第四个参数标记名称
//event[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
//event[1] = CreateEvent(NULL, TRUE, FALSE, NULL); event[] = CreateEvent(NULL, FALSE, FALSE, NULL);
event[] = CreateEvent(NULL, FALSE, FALSE, NULL);
event[] = CreateEvent(NULL, FALSE, FALSE, NULL);
event[] = CreateEvent(NULL, FALSE, FALSE, NULL); hd[] = CreateThread(NULL, , Zhang, NULL, , NULL);
hd[] = CreateThread(NULL, , Li, NULL, , NULL);
hd[] = CreateThread(NULL, , Wang, NULL, , NULL); WaitForMultipleObjects(, hd, TRUE, INFINITE); system("pause");
}

  3. 一对多广播模式:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> //互斥解决线程冲突
//事件解决线程通信
//临界区解决线程冲突
//时间同步线程
HANDLE event[] = { };
HANDLE hd[] = { }; char ch[] = { 'A','B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' };
char str[] = { }; DWORD WINAPI ZhangGirlFriend(void *p)
{
char *pch = p;
printf("I am %c ZhangGirlFrend.\n", *pch); if (*pch == 'A')
{
MessageBoxA(, "", "", );
sprintf(str,"张女友-%c speak: xiaohaha \n", *pch);
SetEvent(event[]);
} int i = ;
while (++i)
{
WaitForSingleObject(event[], INFINITE);
printf("ZhangGirlFriend-%c read %s\n", *pch, str);
Sleep();
ResetEvent(event[]);
} return ;
} void main()
{
//第二个参数代表:自动FALSE(收到一次自动清空一次)、手动TRUE(需要reset)
//第三个参数信号状态
//第四个参数标记名称
event[] = CreateEventA(NULL, TRUE, FALSE, "msg"); //一直等待消息 for (int i = ; i < ; i++)
{
hd[i] = CreateThread(NULL, , ZhangGirlFriend, &ch[i], , NULL);
} WaitForMultipleObjects(, hd, TRUE, INFINITE); system("pause");
}

二. 信号量:

  1. 信号量用作“关卡”的作用:

//信号量-->关卡的作用
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> #define id "Zhang"
#define MAX 3 //0 无限等待
DWORD WINAPI myworker(void *p)
{
int *pint = p;
printf("myworker%d is running...\n", *pint); HANDLE myhsem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, id); //打开一个信号
if (myhsem)
{
printf("myworker%d is waiting...\n", *pint);
//初始时信号为0,为0就会死锁,信号量不减
//不为0的情况下,信号量-1
if (WaitForSingleObject(myhsem, INFINITE) == WAIT_OBJECT_0) //等到了信号
{
printf("myworker%d is getting.\n", *pint);
Sleep(); printf("myworker%d is leaving.\n", *pint);
ReleaseSemaphore(myhsem, , NULL);//释放资源 +1
CloseHandle(myhsem);//执行完成退出
}
} return ;
} void main()
{
//创建信号对象
HANDLE hSEM = CreateSemaphore(NULL, , MAX, id);//开辟一个信号,最大计数是3 int a[] = { ,,,,,,,,, }; HANDLE hd[] = { };
for (int i = ; i < ; i++)
{
hd[i] = CreateThread(NULL, , myworker, a + i, , NULL); //创建10个线程
}
Sleep(); printf("激活线程.\n");
ReleaseSemaphore(hSEM, MAX, NULL);//最多一次放过3个 +3 WaitForMultipleObjects(, hd, TRUE, INFINITE); CloseHandle(hSEM); system("pause");
}

  2. 信号量实现互斥:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> int num = ; //互斥量,只能让一个线程运行,其他休眠
//信号量,可以让多个线程运行,其他线程休眠
//临界区,只能让一个线程运行,其他休眠
//原子操作,操作速度最快
//事件也可以实现互斥
DWORD WINAPI add(void *p)
{
HANDLE myhsem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Hello");
if (myhsem)
{ if (WaitForSingleObject(myhsem, INFINITE) == WAIT_OBJECT_0) //等到了信号
{
for (int i = ; i < ; i++)
{
num++;
} ReleaseSemaphore(myhsem, , NULL);//释放资源 +1
CloseHandle(myhsem);//执行完成退出
}
}
else
{
printf("信号量获取失败.\n");
} return ;
} void main()
{
HANDLE hSEM = CreateSemaphore(NULL, , , "Hello"); HANDLE hd[] = { };
for (int i = ; i < ; i++)
{
hd[i] = CreateThread(NULL, , add, NULL, , NULL); //创建64个线程
}
Sleep(); printf("激活线程.\n");
ReleaseSemaphore(hSEM, , NULL); //一次放过一个 WaitForMultipleObjects(, hd, TRUE, INFINITE); printf("%d\n", num); CloseHandle(hSEM); system("pause");
}

三. 互斥锁:

  相关函数如下:

    第一个 InitializeSRWLock
    函数功能:初始化读写锁
    函数原型:VOID InitializeSRWLock(PSRWLOCK SRWLock);
    函数说明:初始化(没有删除或销毁SRWLOCK的函数,系统会自动清理)

    第二个 AcquireSRWLockExclusive
    函数功能:写入者线程申请写资源。
    函数原型:VOID AcquireSRWLockExclusive(PSRWLOCK SRWLock);

    第三个 ReleaseSRWLockExclusive
    函数功能:写入者线程写资源完毕,释放对资源的占用。
    函数原型:VOID ReleaseSRWLockExclusive(PSRWLOCK SRWLock);

    第四个 AcquireSRWLockShared
    函数功能:读取者线程申请读资源。
    函数原型:VOID AcquireSRWLockShared(PSRWLOCK SRWLock);

    第五个 ReleaseSRWLockShared
    函数功能:读取者线程结束读取资源,释放对资源的占用。
    函数原型:VOID ReleaseSRWLockShared(PSRWLOCK SRWLock);

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> int num = ;
SRWLOCK g_lock; //注意一个线程仅能锁定资源一次,不能多次锁定资源。
DWORD WINAPI read(void *p)
{
AcquireSRWLockShared(&g_lock); //读取期间锁定数据,数据无法被修改 int i = ;
while ()
{
Sleep();
printf("第%d秒num=%d\n", i, num); if (i == )
{
break;
} i++;
} ReleaseSRWLockShared(&g_lock); return ;
} //改变一个变量的时候需要锁定
DWORD WINAPI write(void *p)
{
AcquireSRWLockExclusive(&g_lock); //锁定写入
printf("开始写入...\n");
for (int i = ; i < ; i++)
{
num--;
//Sleep(10);
}
ReleaseSRWLockExclusive(&g_lock);
printf("结束写入...\n");
return ;
} void main()
{
InitializeSRWLock(&g_lock); //初始化互斥锁 CreateThread(NULL, , read, NULL, , NULL); HANDLE hd[];
for (int i = ; i < ; i++)
{
hd[i] = CreateThread(NULL, , write, NULL, , NULL);
}
WaitForMultipleObjects(, hd, TRUE, INFINITE); printf("last=%d\n", num); system("pause");
}

四. 跨进程通信:

1. 信号量mutex 跨进程通信:

  文件mutex1.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> char name[] = "Zhang love Li"; void main()
{
HANDLE mutex = OpenMutexA(MUTEX_ALL_ACCESS, TRUE, name);
if (mutex == NULL)
{
printf("打开失败!\n");
system("pause");
return;
}
printf("等待------\n"); DWORD res = WaitForSingleObject(mutex, );
switch (res)
{
case WAIT_OBJECT_0:
printf("收到信号---\n");
break;
case WAIT_TIMEOUT:
printf("超时没有收到---\n");
break;
case WAIT_ABANDONED:
printf("另外一个进程意外终止---\n");
break;
default:
break;
} CloseHandle(mutex);
system("pause");
}

  文件mutex2.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> char name[] = "Zhang love Li"; void main()
{
HANDLE mutex = CreateMutexA(NULL, TRUE, name);
printf("创建成功!\n");
char ch = getchar(); ReleaseMutex(mutex); //离开互斥区
printf("触发互斥量.\n");
CloseHandle(mutex); system("pause");
}

  运行结果:

 2. 事件 event 跨进程通信:

  文件event.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> char name[] = "Zhang love Li"; //只有mutex可以感知丢失,event无法感知
void main()
{
HANDLE event = CreateEventA(NULL, FALSE, FALSE, name);
printf("创建成功!\n");
char ch = getchar(); SetEvent(event);
printf("触发event.\n");
CloseHandle(event); system("pause");
}

  文件 wait.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> char name[] = "Zhang love Li"; void main()
{
HANDLE event = OpenEventA(EVENT_ALL_ACCESS, TRUE, name);//打开事件
if (event == NULL)
{
printf("打开失败!\n");
system("pause");
return;
}
printf("等待------\n"); DWORD res = WaitForSingleObject(event, );
switch (res)
{
case WAIT_OBJECT_0:
printf("收到信号---\n");
break;
case WAIT_TIMEOUT:
printf("超时没有收到---\n");
break;
case WAIT_ABANDONED:
printf("另外一个进程意外终止---\n");
break;
default:
break;
} CloseHandle(event);
system("pause");
}

 3. 信号 semaphore 跨进程通信:

  semaphore.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> char name[] = "Zhang love Li"; //只有mutex可以感知丢失,event无法感知
void main()
{
HANDLE hsem = CreateSemaphoreA(NULL, , , name);
printf("创建成功!\n");
char ch = getchar(); ReleaseSemaphore(hsem, , NULL);
printf("触发信号量semaphore.\n");
CloseHandle(hsem); system("pause");
}

  wait.c :

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> char name[] = "Zhang love Li"; void main()
{
HANDLE hsem = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, TRUE, name);
if (hsem == NULL)
{
printf("打开失败!\n");
system("pause");
return;
}
printf("等待------\n"); DWORD res = WaitForSingleObject(hsem, );
switch (res)
{
case WAIT_OBJECT_0:
printf("收到信号---\n");
break;
case WAIT_TIMEOUT:
printf("超时没有收到---\n");
break;
case WAIT_ABANDONED:
printf("另外一个进程意外终止---\n");
break;
default:
break;
} CloseHandle(hsem);
system("pause");
}

五. 回调函数与定时器:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> //回调函数,函数指针可以来调用
VOID CALLBACK timerun(void *parg, DWORD timearg, DWORD timehigh)
{
DWORD dwindex = *(DWORD *)parg;
printf("第%d次\n", dwindex);
} void main()
{
HANDLE timer1 = CreateWaitableTimerA(NULL, TRUE, "hello");//创建时钟
if (timer1 == NULL)
{
printf("创建失败!\n");
} LARGE_INTEGER mytime;
mytime.QuadPart = -; //单位是0.1微秒 DWORD dwparam = ; //设置定时器 if (SetWaitableTimer(timer1, &mytime, , timerun, &dwparam, FALSE))//1000 1秒循环一次
{
printf("等待5秒后开始干活!\n");
for (int i = ; i < ; i++, dwparam++) //循环调用多少次
{
SleepEx(INFINITE, TRUE);
}
} CancelWaitableTimer(timer1);//取消定时器
CloseHandle(timer1); system("pause");
}

六. 原子操作:

#include <stdio.h>
#include <stdlib.h> void main()
{
volatile int i = ; //数据被意外改变的时候,强制读内存
int a = i;
printf("i=%d\n", a); //偷偷改变i
__asm
{
mov dword ptr[ebp-],20h //16进制 20h=32
} int b = i;
printf("i=%d\n", b); system("pause");
}

  上面结果在Debug模式下结果为:

        

  在Release模式下结果为:

        

C语言多线程编程二的更多相关文章

  1. linux下C语言多线程编程实例

    用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...

  2. C语言多线程编程

    HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUT ...

  3. Linux C语言多线程编程实例解析

    Linux系统下的多线程遵循POSIX线程接口,称为 pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a.顺便说一下,Linux ...

  4. Linux系统编程@多线程编程(二)

    线程的操作 线程标识 线程的ID表示数据类型:pthread_t (内核中的实现是unsigned long/unsigned int/指向pthread结构的指针(不可移植)几种类型) 1.对两个线 ...

  5. java多线程编程(二)

    1. wait 和 sleep 区别? 1.wait可以指定时间也可以不指定,sleep必须指定时间. 2.在同步中时,对cpu的执行权和锁的处理不同.  wait:释放执行权,释放锁.  sleep ...

  6. java多线程编程(二创建线程)

    1.概念           因为java是完全面向对象的,所以在java中,我们说的线程,就是Thread类的一个实例对象.所以,一个线程就是一个对象,它有自己字段和方法. 2.创建线程 创建线程有 ...

  7. Android多线程编程<二>Handler异步消息处理机制之Message

      Message(消息):       一. Message的字段:    在Android中,Message作为线程之间(主要是子线程和UI主线程之间)数据交换的载体,通过Handler去传递.它 ...

  8. C++多线程编程二

    1. 死锁与解锁: #include <iostream> #include <thread> #include <mutex> using namespace s ...

  9. C语言多线程编程 死锁解析

    1.假设有两个线程 A线程负责输出奇数.B线程负责输出偶数. 2.当A线程进入锁定状态是,主线程突然异常将A线程停止,这时将导致B线程也无法继续执行,处于死锁状态.如下代码: #include < ...

随机推荐

  1. 16.3Sum Closest (Two-Pointers)

    Given an array S of n integers, find three integers in S such that the sum is closest to a given num ...

  2. 基于Bind实现的DNS正反向解析及主从DNS的配置

    一.什么是DNS? 1.1 简单的理解,Domain Name System,是互联网一项核心的服务,他作为一个桥梁可以将域名和IP地址相互因素的一个分布式数据库,能够使人更加方便的访问互联网,而不用 ...

  3. oracle存储过程和游标参考

    oracle open cursor forhttp://www.itpub.net/thread-1874683-1-1.html

  4. asp.net 4高级程序设计( 第4版)文摘

    第一部分 核心概念 第1章 asp.net 简介 第2章 visual studio 第3章 Web窗体 3.2 web窗体处理阶段 页面框架初始化(page.init),用户代码初始化(page.l ...

  5. Gym 101201F Illumination (Two-Sat)

    题意:一个n*n的房子,有很多灯,每个格子只能被上下方向照一次.左右方向照一次,每个灯可以选择上下或是左右照,照明长度以自身位置为中心,占用2*r+1个格子.问能否安排一种方案,使所有格子满足条件. ...

  6. 如何用word文档在博客里发表文章

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  7. Linux中许多常用命令是必须掌握的,这里将我学linux入门时学的一些常用的基本命令分享给大家一下,希望可以帮助你们。

    Linux中许多常用命令是必须掌握的,这里将我学linux入门时学的一些常用的基本命令分享给大家一下,希望可以帮助你们. 这个是我将鸟哥书上的进行了一下整理的,希望不要涉及到版权问题. 1.显示日期的 ...

  8. python ghost.py使用笔记

    ghost.py目前已更新到0.2版本,变化有点大,使用方法上跟0.1还是有点差别的,本文仅以0.1.1版本为例,因为我安装的是这个版本 我用ghost主要用来模拟在网站上的操作,比如登录之类的,当然 ...

  9. 20155308 2016-2017-2 《Java程序设计》第8周学习总结

    20155308 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 第十四章 NIO与NIO2 NIO(New IO)-from JDK1.4 NIO2 -fr ...

  10. spring注解@Value取不到值【转】

    spring注解@Value取不到值 今天在一个项目中发现一个情况,在Service中取不到name值,直接输出了{name}字符串,找了好久,最后在一篇文章中找到解决方案. 解决这个问题的一篇文章( ...