windows下使用Critical Section和Mutex实现线程同步实例

利用critical section 和 Mutex两种不同的线程同步的方法实现生产者消费者问题。生产者线程要能够对一个计数器进行增的操作,并且将其输出在控制台上,消费者线程能够对这个计数器进行减的操作,并将其输出在控制台上。两种线程都共享一个计数器。

其中增、减计数器的数我设置为1~6随机。

测试两种方法的对比,用网上整理出的一张表如下

1、使用CriticalSection 方法时,有一个临界区cs

在将临界区传递给 InitializeCriticalSection 时(或者更准确地说,是在传递其地址时),临界区即开始存在。

初始化之后,代码即将临界区传递给 EnterCriticalSection 和 LeaveCriticalSection API。一个线程自 EnterCriticalSection 中返回后,所有其他调用EnterCriticalSection 的线程都将被阻止,直到第一个线程调用 LeaveCriticalSection 为止。

int count = 0; //counter value
CRITICAL_SECTION cs;//临界区
int maxinum, mininum;//设置counter value最大值,最小值
int producerCallNum = 0, consumerCallNum = 0;//生产者、消费者分别进入临界区次数

2、使用mutex方法时,有一个互斥锁mutex

HANDLE Mutex = NULL;//互斥锁

创建一个互斥器:CreateMutex;

获得互斥器的拥有权:WaitForSingleObject、WaitForMultipleObjects 等一类等待的函数……,第一个线程调用所有其他调用WaitForSingleObject的线程都将被阻止,直到第一个线程ReleaseMutex为止

释放互斥器的拥有权:ReleaseMutex;

3、生产者线程不断交替地执行如下两个阶段:睡眠一段随机时间0~1000,向计数器增加一个随机值,其值位于1~6之间。

DWORD WINAPI producer(LPVOID Param) {
    pthreadID * pID = (pthreadID *)Param;
    while (true) {
        //sleep for a random period of time
        Sleep(rand()%1000);
        srand(count);
        WaitForSingleObject(Mutex, INFINITE);
        // generate
        int add_count = rand() % 6 + 1;
        //判断是否超过最大值
        if (count < maxinum) {
            count += add_count;
            if (count > maxinum) {
                add_count -= count - maxinum;
                count = maxinum;
            }
            printf("Producer%d : produced %d items\n", pID->id, add_count);
        }
        else
            printf("Producer%d : counter value is full, cancel producing...\n", pID->id);
        printf("items num is %d\n", count);
        ReleaseMutex(Mutex);
       //生产者进入临界区,次数增加
        producerCallNum++;
    }
    return 0;
}

消费者线程也可睡眠一段时间,在醒后,对计数器减去一个随机值1~6 之间。

DWORD WINAPI consumer(LPVOID Param) {
    pthreadID * pID = (pthreadID *)Param;
    while (true) {
        //sleep for a random period of time
        Sleep(rand()%1000);
        WaitForSingleObject(Mutex, INFINITE);
        // generate
        srand(count);
        int decrease_count = rand() % 6 + 1;
        //判断是否超过最小值
        if (count > mininum) {
            count -= decrease_count;
            if (count <= mininum) {
                decrease_count -= mininum - count;
                count = mininum;
            }
            printf("Consumer%d : consumed %d items\n", pID->id, decrease_count);
        }
        else
            printf("Consumer%d : counter value is less than mixinum, cancel consuming...\n", pID->id);
        printf("items num is %d\n", count);
        ReleaseMutex(Mutex);
        //消费者进入临界区,次数增加
        consumerCallNum++;
    }
    return 0;
}

使用critical_section方法

#include <cstdlib>
#include <windows.h>
#include <cstdio>
#include "ctime"

int count = 0; //counter value
CRITICAL_SECTION cs;//临界区
int maxinum, mininum;//设置counter value最大值,最小值
int producerCallNum = 0, consumerCallNum = 0;//生产者、消费者分别进入临界区次数

struct pthreadID {
    int id;
};
DWORD WINAPI producer(LPVOID Param) {
    pthreadID * pID = (pthreadID *)Param;
    while (true) {
        //sleep for a random period of time
        Sleep(rand()%1000);
        srand(count);
        EnterCriticalSection(&cs);
        // generate
        int add_count = rand() % 6 + 1;
        //判断是否超过最大值
        if (count < maxinum) {
            count += add_count;
            if (count > maxinum) {
                add_count -= count - maxinum;
                count = maxinum;
            }
            printf("Producer%d : produced %d items\n", pID->id, add_count);
        }
        else
            printf("Producer%d : counter value is full, cancel producing...\n", pID->id);
        printf("items num is %d\n", count);
        LeaveCriticalSection(&cs);
        //生产者进入临界区,次数增加
        producerCallNum++;
    }
    return 0;
}
DWORD WINAPI consumer(LPVOID Param) {
    pthreadID * pID = (pthreadID *)Param;
    while (true) {
        //sleep for a random period of time
        Sleep(rand()%1000);
        EnterCriticalSection(&cs);
        // generate
        srand(count);
        int decrease_count = rand() % 6 + 1;
        //判断是否超过最小值
        if (count > mininum) {
            count -= decrease_count;
            if (count <= mininum) {
                decrease_count -= mininum - count;
                count = mininum;
            }
            printf("Consumer%d : consumed %d items\n", pID->id, decrease_count);
        }
        else
            printf("Consumer%d : counter value is less than mixinum, cancel consuming...\n", pID->id);
        printf("items num is %d\n", count);
        LeaveCriticalSection(&cs);
        //消费者进入临界区,次数增加
        consumerCallNum++;
    }
    return 0;
}
int main(int argc, char * argv[]) {
    srand(count);
    int ThreadP_size = 5, ThreadC_size = 5;
    int sleeptime;
    pthreadID * pid, *cid;  //标记生产者和消费者
    InitializeCriticalSection(&cs);
    HANDLE *ThreadHandleP, *ThreadHandleC; //生产者和消费者线程
    DWORD *ThreadIdP, *ThreadIdC; //存储生产者和消费者线程ID
    printf("please input the number of ThreadProducer : \n");
    scanf("%d", &ThreadP_size);
    printf("please input the number of ThreadConsumer : \n");
    scanf("%d", &ThreadC_size);
    printf("please input the maxinum of counter values : \n");
    scanf("%d", &maxinum);
    printf("please input the mininum of counter values : \n");
    scanf("%d", &mininum);
    printf("please input the main function sleeptime(s) after create threads : \n");
    scanf("%d", &sleeptime);
    printf("the data can see at ‘CriticalSection_output.txt‘\n");
    //动态分配
    ThreadHandleP = (HANDLE *)malloc(ThreadP_size * sizeof(HANDLE));
    ThreadHandleC = (HANDLE *)malloc(ThreadC_size * sizeof(HANDLE));
    ThreadIdP = (DWORD *)malloc(ThreadP_size * sizeof(DWORD));
    ThreadIdC = (DWORD *)malloc(ThreadC_size * sizeof(DWORD));
    pid = (pthreadID*)malloc(ThreadP_size * sizeof(DWORD));
    cid = (pthreadID*)malloc(ThreadC_size * sizeof(DWORD));
    freopen("CriticalSection_output.txt", "w", stdout);
    printf("the number of ThreadProducer : %d\n", ThreadP_size);
    printf("the number of ThreadConsumer : %d\n", ThreadC_size);
    printf("the maxinum of counter values : %d\n", maxinum);
    printf("the mininum of counter values : %d\n", mininum);
    printf("the main function sleeptime(s) after create threads : %d (s) \n", sleeptime);
    //create producer thread(s)
    for (int i = 0; i < ThreadP_size; i++) {
        pid[i].id = i + 1;
        ThreadHandleP[i] = CreateThread(NULL, 0, producer, &pid[i], 0, &ThreadIdP[i]);
    }

    //create consumer thread(s)
    for (int i = 0; i < ThreadC_size; i++)
    {
        cid[i].id = i + 1;
        ThreadHandleC[i] = CreateThread(NULL, 0, consumer, &cid[i], 0, &ThreadIdC[i]);
    }
    //sleep
    Sleep(sleeptime*1000);
    //exit
    printf("the producer  produced %d times\n", producerCallNum);
    printf("the consumer consumed %d times\n", consumerCallNum);
    fclose(stdout);
    return 0;
}

使用mutex方法实现

#include <cstdlib>
#include <windows.h>
#include <cstdio>
#include "ctime"

int count = 0; //counter value
HANDLE Mutex = NULL;//互斥锁
int maxinum, mininum;//设置counter value最大值,最小值
int producerCallNum = 0, consumerCallNum = 0;//生产者、消费者分别进入临界区次数

struct pthreadID {
    int id;
};
DWORD WINAPI producer(LPVOID Param) {
    pthreadID * pID = (pthreadID *)Param;
    while (true) {
        //sleep for a random period of time
        Sleep(rand()%1000);
        srand(count);
        WaitForSingleObject(Mutex, INFINITE);
        // generate
        int add_count = rand() % 6 + 1;
        //判断是否超过最大值
        if (count < maxinum) {
            count += add_count;
            if (count > maxinum) {
                add_count -= count - maxinum;
                count = maxinum;
            }
            printf("Producer%d : produced %d items\n", pID->id, add_count);
        }
        else
            printf("Producer%d : counter value is full, cancel producing...\n", pID->id);
        printf("items num is %d\n", count);
        ReleaseMutex(Mutex);
       //生产者进入临界区,次数增加
        producerCallNum++;
    }
    return 0;
}
DWORD WINAPI consumer(LPVOID Param) {
    pthreadID * pID = (pthreadID *)Param;
    while (true) {
        //sleep for a random period of time
        Sleep(rand()%1000);
        WaitForSingleObject(Mutex, INFINITE);
        // generate
        srand(count);
        int decrease_count = rand() % 6 + 1;
        //判断是否超过最小值
        if (count > mininum) {
            count -= decrease_count;
            if (count <= mininum) {
                decrease_count -= mininum - count;
                count = mininum;
            }
            printf("Consumer%d : consumed %d items\n", pID->id, decrease_count);
        }
        else
            printf("Consumer%d : counter value is less than mixinum, cancel consuming...\n", pID->id);
        printf("items num is %d\n", count);
        ReleaseMutex(Mutex);
        //消费者进入临界区,次数增加
        consumerCallNum++;
    }
    return 0;
}
int main(int argc, char * argv[]) {
    srand(count);
    int ThreadP_size = 5, ThreadC_size = 5;
    int sleeptime;
    Mutex = CreateMutex(NULL, FALSE, NULL);
    pthreadID * pid, *cid;  //标记生产者和消费者
    InitializeCriticalSection(&cs);
    HANDLE *ThreadHandleP, *ThreadHandleC; //生产者和消费者线程
    DWORD *ThreadIdP, *ThreadIdC; //存储生产者和消费者线程ID
    printf("please input the number of ThreadProducer : \n");
    scanf("%d", &ThreadP_size);
    printf("please input the number of ThreadConsumer : \n");
    scanf("%d", &ThreadC_size);
    printf("please input the maxinum of counter values : \n");
    scanf("%d", &maxinum);
    printf("please input the mininum of counter values : \n");
    scanf("%d", &mininum);
    printf("please input the main function sleeptime(s) after create threads : \n");
    scanf("%d", &sleeptime);
    printf("the data can see at ‘Mutex_output.txt‘\n");
    ThreadHandleP = (HANDLE *)malloc(ThreadP_size * sizeof(HANDLE));
    ThreadHandleC = (HANDLE *)malloc(ThreadC_size * sizeof(HANDLE));
    ThreadIdP = (DWORD *)malloc(ThreadP_size * sizeof(DWORD));
    ThreadIdC = (DWORD *)malloc(ThreadC_size * sizeof(DWORD));
    pid = (pthreadID*)malloc(ThreadP_size * sizeof(DWORD));
    cid = (pthreadID*)malloc(ThreadC_size * sizeof(DWORD));
    freopen("Mutex_output.txt", "w", stdout);
    printf("the number of ThreadProducer : %d\n", ThreadP_size);
    printf("the number of ThreadConsumer : %d\n", ThreadC_size);
    printf("the maxinum of counter values : %d\n", maxinum);
    printf("the mininum of counter values : %d\n", mininum);
    printf("the main function sleeptime(s) after create threads : %d (s) \n", sleeptime);
    //create producer thread(s)
    int i;
    for (i = 0; i < ThreadP_size; i++) {
        pid[i].id = i + 1;
        ThreadHandleP[i] = CreateThread(NULL, 0, producer, &pid[i], 0, &ThreadIdP[i]);
    }

    //create consumer thread(s)
    for (i = 0; i < ThreadC_size; i++)
    {
        cid[i].id = i + 1;
        ThreadHandleC[i] = CreateThread(NULL, 0, consumer, &cid[i], 0, &ThreadIdC[i]);
    }
    //sleep
    Sleep(sleeptime*1000);
    //exit
    printf("the producer  produced %d times\n", producerCallNum);
    printf("the consumer consumed %d times\n", consumerCallNum);
    fclose(stdout);
    return 0;
}

对比critical_section与mutex两种方法 主函数等待相同时间,分别看两种方法生产者,消费者进入临界区次数 第一次测试数据为

生产者线程数: 5

消费者线程数: 4

最大计数器值: 20

最小计数器值: 3

主函数等待时间: 4 (s)

第二次测试数据为

生产者线程数: 6

消费者线程数: 4

最大计数器值: 25

最小计数器值: 3

主函数等待时间: 1 (s)

第三次测试数据为

生产者线程数: 6

消费者线程数: 4

最大计数器值: 28

最小计数器值: 5

主函数等待时间: 10 (s)

第四次测试数据为

生产者线程数: 7

消费者线程数: 7

最大计数器值: 40

最小计数器值: 8

主函数等待时间: 30 (s)

消费者线程数: 4

最大计数器值: 30

最小计数器值: 10

主函数等待时间: 60 (s)

Pn代表生产者进入临界区次数,Cn代表消费者进入临界区次数

发现

critical_section

Mutex

两者性能差别不是很大,最后发现可能每次进入临界区前都会sleep一段时间导致远远大于EnterCriticalSection(&cs)与WaitForSingleObject (Mutex, INFINITE);的执行时间。

于是我就在进入临界区之前,生产者线程和消费者线程都执行5000次的EnterCriticalSection(&cs)与LeaveCriticalSection(&cs)

或WaitForSingleObject (Mutex, INFINITE)与ReleaseMutex(Mutex);

同样地对mutex的方法进行相应的操作

第一次测试数据为

生产者线程数: 5

消费者线程数: 4

最大计数器值: 20

最小计数器值: 3

主函数等待时间: 4 (s)

第二次测试数据为

生产者线程数: 6

消费者线程数: 4

最大计数器值: 25

最小计数器值: 3

主函数等待时间: 1 (s)

第三次测试数据为

生产者线程数: 6

消费者线程数: 4

最大计数器值: 28

最小计数器值: 5

主函数等待时间: 10 (s)

第四次测试数据为

生产者线程数: 7

消费者线程数: 7

最大计数器值: 40

最小计数器值: 8

主函数等待时间: 30 (s)

第五次测试数据为

生产者线程数: 7

消费者线程数: 4

最大计数器值: 30

最小计数器值: 10

主函数等待时间: 60 (s)

Pn代表生产者进入临界区次数,Cn代表消费者进入临界区次数

发现

很明显地,Mutex比critical_section方法进入临界区的次数较少,所以如 果为非跨进程的话,critical_section比Mutex占优些。

时间: 2024-08-02 19:17:13

windows下使用Critical Section和Mutex实现线程同步实例的相关文章

转:Windows下的PHP开发环境搭建——PHP线程安全与非线程安全、Apache版本选择,及详解五种运行模式。

原文来自于:http://www.ituring.com.cn/article/128439 Windows下的PHP开发环境搭建——PHP线程安全与非线程安全.Apache版本选择,及详解五种运行模式. 今天为在Windows下建立PHP开发环境,在考虑下载何种PHP版本时,遭遇一些让我困惑的情况,为了解决这些困惑,不出意料地牵扯出更多让我困惑的问题. 为了将这些困惑一网打尽,我花了一下午加一晚上的时间查阅了大量资料,并做了一番实验后,终于把这些困惑全都搞得清清楚楚了. 说实话,之所以花了这么

Windows下利用rsync实现邮件服务器数据的同步

Windows下利用rsync实现邮件服务器数据的同步 背景环境 对系统管理员来说,平时的工作重心应该集中在维护 系统正常运转,能够正常提供服务上,这里往往牵涉到 一个数据备份的问题,在我所了解的情况中,有80%的系统管理员不是太关心自己服务器的安全性,但往往对 备份镜像的技术相当感兴趣,但由于商业产品的软硬件价格都相当高昂,因此往往会选择自由软件.rsync就 是这样的软件,它可以满足绝大多数要求不是特 别高的备份需求.适用于数据不是很大,海量小的文件的存储备份,结合服务器本身的磁盘阵列技术,

Windows下的PHP开发环境搭建——PHP线程安全与非线程安全、Apache版本选择,及详解五种运行模式。

今天为在Windows下建立PHP开发环境,在考虑下载何种PHP版本时,遭遇一些让我困惑的情况,为了解决这些困惑,不出意料地牵扯出更多让我困惑的问题. 为了将这些困惑一网打尽,我花了一下午加一晚上的时间查阅了大量资料,并做了一番实验后,终于把这些困惑全都搞得清清楚楚了. 说实话,之所以花了这么多时间,很大程度上是由于网上的资料几乎全都是支离破碎.以讹传讹的.既然我已经搞懂了,就花时间整理出来,即方便自己看,也便于大家阅读.相信通过这篇文章,可以解答很多在Windows下搭建PHP开发环境的朋友的

Windows下找到JVM占用资源高的线程

与linux下top命令直接显示进程下线程资源占用不同,Windows下默认任务管理器只能显示出进程的资源占用,jconsle等工具也只能显示出java进程资源占用,无法显示出进程能具体线程的资源占用,为此需要用到一个工具processExplorer. 1.用任务管理器或jconsle工具占用资源最高的java进程pid: 2.用processExplorer工具找到这个进程下线程的资源占用情况,找到占用资源最高的线程id,将其转换为16进制显示: 3.jconsle或jstack java进

windows 下一个进程能开多少个线程

进程里面创建线程数收到总线的限制,32位最多只能访问4G内存,其中2G为用户态使用:而每个线程都有自己的栈大小:测试发现使用createthread创建线程:当栈设置为1M时,只能开大约1426个线程:当设置为512k时,可以开2244个线程,设置为256k时,可以开3122个线程,所以在我们做sock通信服务器时,需要注意,如果一个客户端 connect进来,就用一个线程对它进程处理的话,服务端会收到线程数的限制:测试代码如下: server // server.cpp : 定义控制台应用程序

Windows下MySQL的主从热备(自动同步)配置

本配置方法适用于5.1之后的版本,个人在5.5上配置成功(5.1之前版本请参考另外的配置说明) 环境说明: Master:192.168.1.200 Slave:192.168.1.210 MySQL 的 Master 配置: 配置my.ini: [mysqld] # The TCP/IP Port the MySQL Server will listen on port=3306 server-id=200 log-bin=mysql-bin relay-log=relay-bin relay

Critical Section Object

Critical Section  Object  From MSDN Critical Section Objects A critical section object provides synchronization similar to that provided by a mutex object, except that a critical section can be used only by the threads of a single process. Event, mut

Linux下线程同步的几种方法

Linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量. 一.互斥锁(mutex) 锁机制是同一时刻只允许一个线程执行一个关键部分的代码.  1. 初始化锁 int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr); 其中参数 mutexattr 用于指定锁的属性(见下),如果为NULL则使用缺省属性. 互斥锁的属性在创建锁的时候指定,在LinuxThreads实

Windows 互斥对象在线程同步上的运用

互斥对象在线程同步时的使用 1 多线程在资源共享的时候出现的问题 在程序中如果不同线程对同一个对象进行操作的话就有可能出现因为线程切换而导致的问题.例如下面的程序 #include <stdio.h> #include <WinSock2.h> #include <iostream> using namespace std; #pragma comment(lib,"ws2_32.lib") DWORD WINAPIfun1Proc(LPVOID l