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

  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. 数据库 alert.log 日志中出现 "[Oracle][ODBC SQL Server Wire Protocol driver][SQL Server] 'RECOVER'"报错信息

    现象描述: (1).数据库通过调用透明网络实现分布式事务,但透明网关停用后,失败的分布式事务并未清理. (2).数据库 alert 日志 Thu Sep 06 06:53:00 2018 Errors ...

  2. transform.rotation和GetComponent<Rigidbody>().MoveRotation

    同时在UPDATE和FIXED UPDATE中调整 旋转 并未出现闪,而是一直以UPDATE中的为准,可认为MoveRotation调用后在UPDATE中生效 using System.Collect ...

  3. IoC和DI的区别

    ------------------siwuxie095                                     IoC 和 DI 的区别         1.区别     (1)Io ...

  4. [Selenium]怎样等待元素出现之后再消失,譬如Loading icon

    界面上有些元素是要先等它出现,再等它消失,譬如loading icon 这个是等多个loading icon出现后消失 /** * Wait for loading icon disappear in ...

  5. Java NIO API详解(转)

    原文连接: http://www.blogjava.net/19851985lili/articles/93524.html 感谢原作者 NIO API 主要集中在 java.nio 和它的 subp ...

  6. Docker 基本原理

    1 什么是Docker? Docker是基于Go语言实现的云开源项目.Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,也就是通过对应用组件的封装.分 ...

  7. CoderForces 689A Mike and Cellphone (水题)

    题意:给定一个手机键盘数字九宫格,然后让你判断某种操作是不是唯一的,也就是说是不是可以通过平移也能实现. 析:我的想法是那就平移一下,看看能实现,就四种平移,上,下,左,右,上是-3,要注意0变成8, ...

  8. 深海划水队项目--七天冲刺之day6

    站立式会议:由于有位项目组成员回家了,所以由微信群在线讨论代替. 昨天已完成的任务:界面优化,实现方块的移动,旋转和下降. 今天已完成的任务:设置游戏按键,检查重合.检查是否超出边界.检查是否可以下落 ...

  9. EBS请求查找运行详细信息

    --查找运行请求时间,参数等(可以是某用户的,某个报表) select c.user_name,       papf.full_name,       b.user_concurrent_progr ...

  10. scvmm sdk之powershell(一)

    shell表示计算机操作系统中的壳层,与之相对的是内核,内核不能与用户直接交互,而是通过shell为用户提供操作界面,shell分为两类,一种提供命令行界面,一种提供图形界面.windows powe ...