Windows下多线程数据同步互斥的有关知识



对于操作系统而言,在并行程序设计中难免会遇到数据同步和共享的问题,本文针对这个问题,以windows系统为例回顾一下资源同步的相关问题。要点如下:

1.同步和数据共享

 数据征用

2.同步原语

    1.互斥和临界区

    2.自旋锁

    3.信号量

    4.读写锁

    5.屏障

    6.原子操作与无锁代码

3.进程和进程间通信

    1.共享内存和映射文件

    2.条件变量

    3.信号和事件

    4.消息队列

    5.命名管道

    6.socket网络栈

一,基础知识




知识点:句柄

许多windows API函数都返回句柄。句柄只是无符号整数,但却有特殊的用途。返回句柄的windows API 调用实际上是在内核空间创建某个资源,句柄只是这个资源的索引。当应用程序使用完该资源后,就可调用CloseHandle()使内核释放相关的内核空间资源。

创建线程的3种不同的方式

 

#include "stdafx.h"

#include<windows.h>
#include<process.h>

DWORD WINAPI mywork1( LPVOID lpParameter)
{
    printf("CreatThread thread %i\n",GetCurrentThreadId());
    return 0;
}

unsigned int __stdcall mywork2(void *data)
{
    printf("_beginthreadex thread %i\n",GetCurrentThreadId());
    return 0;
}

void mywork3(void * data)
{
    printf("_beginthreade thread %i\n",GetCurrentThreadId());

}

int _tmain(int argc, _TCHAR* argv[])
{

    HANDLE h1,h2,h3;
    h1 = CreateThread(0,0,mywork1,0,0,0);

    h2 = (HANDLE)_beginthreadex(0,0,&mywork2,0,0,0);
    WaitForSingleObject(h2,INFINITE);
    CloseHandle(h2);

    h3 = (HANDLE)_beginthread(&mywork3,0,0);
    getchar();
    return 0;
}

       调用_beginthread()是个吸引人的选择,这个函数的参数较少,并且在线程退出后清除句柄。但是,如果线程终止,则_beginthread()调用返回的句柄将是无效的,或是被重用的,因此无法查询线程的状态,甚至无法肯定线程句柄是最初指向同一线程的句柄。

加上getchar()的区别

二,同步和资源共享的方式



判断一个数是否为素数:

#include<math.h>

int isprime(int number)

{

int i;

for( i = 2; i < (int) (sqrt((float)number) + 1.0); i++)

{

    if(number % i == 0 ){ return 0;}

}

return 1;

}

测试给定范围内数字是否为素数的算法,如果两个线程同时访问变量counter,这将导致数据征用,正确的代码需要对递增变量counter的操作进行保护。

volatile int counter = 0;

unsigned int __stdcall test(void *)

{

while(counter < 100)

{

    int number = counter++;

//c++格式话输出要用cout对象的方法来控制

    printf("ThreadID %i value = %i    is prime  = %i  \n", GetCurrentThreadId(), number , isprime(number) );

}

return 0;

}

1.保护对临界区代码的访问:

// testofCriticalSection.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <math.h>

volatile int counter = 0;
CRITICAL_SECTION critical;

int isprime(int number)
{

    int i;
    for( i = 2; i < (int) (sqrt((float)number) + 1.0); i++)
    {
        if(number % i == 0 ){ return 0;}
    }
    return 1;
}

unsigned int __stdcall test(void *)
{
    while (counter < 100)
    {
        while ( !TryEnterCriticalSection( &critical)){}
        int number = counter++;
        LeaveCriticalSection( &critical);
        printf("ThreadID %i; value = %i, is prime = %i\n",
            GetCurrentThreadId(), number, isprime(number));
    }
    return 0;
}

/*
unsigned int __stdcall test(void *)
{
    while (counter < 100)
    {
        EnterCriticalSection( &critical);
        int number = counter++;
        LeaveCriticalSection( &critical);
        printf("ThreadID %i; value = %i, is prime = %i\n",
            GetCurrentThreadId(), number, isprime(number));
    }
    return 0;
}
*/
int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE h1, h2;
    InitializeCriticalSection( &critical);
    h1 = (HANDLE)_beginthreadex(0, 0, &test,(void*)0, 0, 0);
    h2 = (HANDLE)_beginthreadex(0, 0, &test,(void*)0, 0, 0);
    WaitForSingleObject(h1,INFINITE);//
    WaitForSingleObject(h2,INFINITE);
    CloseHandle(h1);
    CloseHandle(h2);
    getchar();
    DeleteCriticalSection( &critical);
    return 0;
}

使线程休眠然后再唤醒线程非常耗时,因为这涉及进入内核。所有临界区在设计上都应保证耗时尽可能短。要谨记,很可能线程进入休眠时,原处于临界区的线程已经离开。因此,令等待线程休眠后再唤醒浪费了很多时间。

有两种选择解决上述问题:

1.使用TryEnterCriticalSection()避免让调用线程休眠

2.面向临界区设定旋转计数的方法

InitializeCriticalSetionAndSpinCount( &critical,1000)

SetCriticalSectionSpinCount( &critical, 1000)

参考文献:

戈夫. 多核应用编程实战[M]. 人民邮电出版社, 2013.

时间: 2024-10-29 15:23:33

Windows下多线程数据同步互斥的有关知识的相关文章

windows下用SyncToy 同步电脑文件

  在部分系统规划中,需要实现资料夹的同步,这时我们就考虑使用Microsoft同步工具SyncToy,配合Windows自带的计划任务.这次将以一个案例来对两台服务器中存放ASP站点程序的文件夹进行自动同步.SyncToy是微软在2005年10月发布的,该工具现在的版本为2.1,发布日期为11/24/2009,是一款用于Windows XP/2003/Win7操作系统上免费的.易于使用的同步工具.它提供了简洁的操作界面.简单的使用方法和高度的自定义功能,可以帮助我们从繁重的拷贝.移动及同步不同

Ubuntu Server Rsync服务端与Windows cwRsync客户端数据同步配置方法_服务器其它

说明:1.Rsync服务端 系统:Ubuntu Server 11.10 IP地址:192.168.21.168 数据存放目录:/home/mysql_data2.cwRsync客户端 系统:Windows Server 2003 IP地址:192.168.21.130 同步的目录:D:\mysql_data实现目的:cwRsync客户端每天凌晨3:00钟自动同步Rsync服务端/home/mysql_data目录中的数据到D:\mysql_data目录一.Rsync服务端配置 1.开启防火墙t

windows下mysql双向同步备份实现方法_win服务器

1.1 环境搭建 准备两台Windows NT 主机,分别安装好iKEY Server windows 版本,确定版本无误,确保mysql服务正常启动,确保两台主机处于同一个局域网中,确定好哪台做为主.备机器,假设A为主机,B为备机,假设A主机IP地址为:192.168.1.101,B主机IP地址为192.168.1.102 1.2 创建同步帐户 分别在A.B节点上登陆mysql 数据库,创建同步帐户并赋予同步权限,如下: A节点操作: 运行cmd, cd进入iKEY版本安装目录下的iKEY\m

C#-多线程数据同步容易出现的异常问题

问题描述: 当多个线程同时并发读写数据库的时候会抛出异常,这是比较典型的多线程并发同步所带来的问题,因为集合在读的过程中是不容许我们修改的,因此就需要引入锁的概念,加上读写锁就不会出现问题. 集合类通常不是线程安全的,多个阅读器可以安全的读取集合.但是对集合的任何修改都将为访问集合的所有线程生成不明确的结果.使用以下任何方法都可以令集合类是线程安全的 (1) 使用Synchronized 方法,则从该类派生包装,并通过该包装以独占方式访问集合 (2) 如果该类没有Synchronized 方法,

windows lua 多线程 线程同步

今天在改一个程序,改成部分逻辑用lua写,这个程序是多线程的.将程序中部分逻辑改成lua之后,各种非法访问内存错误,各种奇奇怪怪的问题,不分时间,不分地点的出现崩溃.从调用堆栈来看,基本都是使用lua造成的.在多线程中使用lua_newthread得到的lus_State仍然有时候程序会崩溃.基本上可以确定为多线程中操作lua 的问题了. 前几天我转载的一篇文章,文章写了关于lua多线程的作法.作法有二 1.每一个线程函数用lua_newthread产生一个新的lua_state 以后对lua操

Windows 95多线程间同步事件的控制方法

摘要:在Windows 95中所有的应用程序实际上都以是线程的方式运行的.在设计多线程应用程序中有时必须在线程之间保持一定的同步关系,才能使用户能够对独立运行的线程进行有效的控制.为此本文在简要介绍Windows 95中线程的概念及其创建方法后,提出了一种在多线程之间利用 event对象实现事件同步的控制方法.最后还介绍了在不同应用程序之间进行同步事件控制的方法,这种方法使得不同应用程序进行相互间的同步事件控制变得很简单. 关键词:Windows95 线程 同步事件 event 对象 Win32

Windows下的数据恢复工具最好用的15介绍

下面的列表包含了15款数据恢复软件.这些软件相对而言非常容易上手.不过要注意,本文提到的这些软件都是针对Windows平台而言,并且是免费软件.15款windows的数据恢复工具. 15. Recuva 这是能获取到的免费文件恢复工具中最好的一款,没有之一.你可以用该软件恢复硬盘上的.内存卡中的.移动硬盘甚至CD和DVD上的文件.它兼容目前所有的最新版本的 windows,当然也有64位的版本.你可以自己下载一个可安装的版本,后者使用一个免安装版本,两者都由Piriform提供. 14. Pur

用脚本模式配置数据同步

大数据开发套件里可以通过配置同步任务,实现数据在不同数据源之间的迁移.但是因为目前只部署在华东1(参考文档),有一些特殊网络环境可能无法覆盖到.比如VPC下的DRDS或者其他区域自建数据库内网就不通了.不过套件还提供了脚本模式+调度资源设置这2个大杀器,满足各种复杂场景下的数据同步功能. 本文就数据从MaxCompute的数据导出到VPC下的DRDS为例,详细介绍如何使用这两种方法来实现灵活的数据同步. 同步原理 首先介绍下大数据开发套件的同步任务是怎么做的. (这个图片来自这里) 常有人以同步

用cwrsync同步windows下数据的简单配置方法_win服务器

cwrsync下载地址 http://sourceforge.net/projects/sereds/files/cwRsync 或者到 s.jb51.net下载 cwrsync分客户端和服务端两部分,拿cwrsync 4.0.版来说,分别对应cwRsync_4.0.5_Installer.zip和cwRsyncServer_4.0.5_Installer.zip 安装: 客户端安装比较简单,一直下一步就可以了. 服务端安装到Service Account这一步的时候,这一步会建立cwrsync