分享

VC windows api 多线程---互斥量、信号量、临界值

 恩赐野兔 2011-06-22
VC windows api 多线程---互斥量


    互斥量的用途和临界区很像。它与临界区的差别在于可以跨线程使用,可以用来同步进行多个线程间的数据访问,但是是以牺牲速度为代价的。只有临界区是非核心对象,那么互斥量就是一个核心对象了。核心对象的特点是有所谓的引用计数。所著一个未被拥有的互斥量,比锁住一个未被拥有的临界区需要花费几乎100倍的时间(数据引用自《Visual C++ 6.0编程学习捷径》)。

 Win32 API有一套互斥量的支持函数:


创建互斥量.
 * @param lpMutexAttributes 指定安全属性,NULL表示使用默认的属性.
 * @param bInitialOwner 指出创建互斥量的线程是否要成为该互斥量的最初拥有.
 * TRUE表示拥有,因此互斥量将处于无信号状态.
 * FALSE表示互斥量不被任何现成拥有,因此处于有信号状态.
 * @param lpName为NULL或标识该互斥量的一个字符串的地址,任何进程或线程都可以根据此名称使用该互斥量.
 * 当应用程序调用CreateMutex()函数时,系统分配一个互斥量的核心对象,把它的名字设为lpName所致的字符串.
 * 该名字在进程间共享互斥量。CreateMutex()返回一个标识新互斥量对象的进程相关的句柄.
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);

 

打开互斥量.
 * @param dwDesiredAccess 可设置为MUTEX_ALL_ACCESS或SYNCHRONIZE.
 * @param bInheritHandle 指出该进程创建的子进程能否继承该互斥量.
 * @param lpName 指定互斥量的名字.
HANDLE OpenMutex(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);

 

释放互斥量.
 * @param hMutex 要释放的互斥量的句柄.
BOOL ReleaseMutex(HANDLE hMutex);

 

 

 

-------------------------------------------
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>

#define  threadnum 10

typedef struct THREADDATA
{
   int id;
   char name[10];
   int sleep;
}THREADDATA;


HANDLE handleMutex;

char * str;

DWORD WINAPI ThreadProc( LPVOID lpParam )
{
   THREADDATA *data=(THREADDATA *)lpParam;
   //WaitForSingleObject(handleMutex,INFINITE);
   for(int i=0;i<10;i++)
   {
    WaitForSingleObject(handleMutex,INFINITE);
    printf("thread%d:%d\n",data->id,i);
    ReleaseMutex(handleMutex);
    Sleep(data->sleep);

   }
 //  ReleaseMutex(handleMutex);
   return 0;
}

int main(int argc, char* argv[])
{
   str=(char*)malloc(30);
   THREADDATA  pData[threadnum];
   DWORD dwThreadId[threadnum];
   HANDLE hThread[threadnum]; 

   handleMutex= CreateMutex(NULL,false,NULL);

   for(int i=0;i<threadnum;i++)
   {
     pData[i].id=i;
     sprintf(pData[i].name,"yuguoqing");
     pData[i].sleep=i*10;
     hThread[i] = CreateThread(NULL,0,ThreadProc, pData+i, 0,  dwThreadId+i);
   }

    WaitForMultipleObjects(threadnum, hThread, TRUE, INFINITE);

    return 0;
} 

VC windows api 多线程---信号量

 


信号量(Semaphore)和互斥量一样,属于内核对象。它自动执行可用资源查询的测试,如果有可用资源,则可用资源的计数减少,从而避免其它线程请求资源。当该线程释放该资源后,可用资源计数增加,则操作系统允许另一个线程请求资源。

信号量与临界区和互斥量的不同在于,它不能被认为属于某个线程。也就是说,一个线程可以等待信号量对象(减少它的资源计数),而另一个线程释放该对象(增加它的资源计数)。

Win32 API提供了几个函数用于支持信号量。使用Win32 API产生一个信号量,必须首先调用CreateSemaphore()函数,该函数描述如下:

创建一个信号量
 
*@param lpSemaphoreAttributes 指定安全属性,如果是NULL就表示使用默认属性。
 
*@param lInitialCount 用于指定该信号量的初始资源计数,必须大于或等于0,并且小于或等于lMaximumCount。
 
*@param lMaximumCount 指定信号量的最大资源计数。
 
*@param lpName 是赋给信号量的字符串名字。
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);     

 

你可以根据信号量的字符串名字得到该信号量的句柄: 
 
*@param dwDesiredAccess 访问方式,同互斥量参数。
 
*@param bInheritHandle 继承特性,同互斥量参数。
 
*@param lpName 信号量名字。
HANDLE OpenSemaphore(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName);     

 

释放信号量函数:
 
*@param hSemaphore 信号量的句柄。
 
*@param lReleaseCount指信号量现值的增额,该值必须大于0。
 
*@param lpPreviousCount 传回信号量原来的计数,可以为NULL。
BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);
      
释放信号量函数与释放互斥量函数形式相同,但不同之处在于:
一、任意线程可以在任意时刻调用此函数,因为信号量对象不为某个线程拥有。
二、ReleaseSemaphore()函数可以用大于1的大小来增加信号量的资源计数。


---------------------------------------

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>

#define  threadnum 10

typedef struct THREADDATA
{
   int id;
   char name[10];
   int sleep;
}THREADDATA;


HANDLE handleSemaphore;
char * str;

DWORD WINAPI ThreadProc( LPVOID lpParam )
{
   THREADDATA *data=(THREADDATA *)lpParam;
 
   WaitForSingleObject(handleSemaphore,INFINITE);
   for(int i=0;i<10;i++)
   {
 // WaitForSingleObject(handleSemaphore,INFINITE);
   printf("thread%d:%d\n",data->id,i);
 // ReleaseSemaphore(handleSemaphore,1,NULL);
   Sleep(data->sleep);

   }
   ReleaseSemaphore(handleSemaphore,1,NULL);
   return 0;
}

int main(int argc, char* argv[])
{
   str=(char*)malloc(30);
   THREADDATA  pData[threadnum];
   DWORD dwThreadId[threadnum];
   HANDLE hThread[threadnum];

   handleSemaphore=CreateSemaphore(NULL,1, 2,"thread");

   for(int i=0;i<threadnum;i++)
   {
     pData[i].id=i;
     sprintf(pData[i].name,"yuguoqing");
     pData[i].sleep=i*10;
     hThread[i] = CreateThread(NULL,0,ThreadProc, pData+i, 0,  dwThreadId+i);
   }

    WaitForMultipleObjects(threadnum, hThread, TRUE, INFINITE);
    return 0;
}

VC windows api 多线程---临界区



在有几个线程并行运行的环境中,同步不同线程的活动是非常重要的。一般说来,一个线程使自己与另一个线程同步的方法是让自己睡眠。但线程睡眠时,操作系统不再为它调度CPU时间,因此它停止了执行。不过,就在它睡眠之前,它告诉系统要让它恢复执行,必须有什么“特殊事件”发生。操作系统记住该线程的请求,监视着“特殊事件”是否发生以及何时发生。当它发生时,线程才又能够加入到CPU时间等待队列中。一旦被预订,线程就能继续执行了。此时,线程就将它的执行与时间的发生取得了同步。

    Windows操作系统提供了设定“特殊事件”的方法,就是使用同步对象。我将在今后学习常用的四种同步对象:临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)。

    上述四种同步对象,除了临界区外都是内核对象。临界区不被操作系统的低级部件管理,而且不能使用句柄来操纵,是最易于使用和理解的同步对象。

    当多个线程共享对同一数据的访问时,线程之间可能会有干扰。一个临界区对象保护一段代码不被多于一个线程访问。在所有的同步对象中,临界区是最容易使用的,但是,一个临界区对一个进程或DLL是有限的,不能被其他进程共享,只能用于同步单个进程中的线程。临界区不是Windows核心对象,它和核心对象不同,存在于进程的内存空间中。

    Win32 API提供了几个临界区函数:

void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

    CRITICAL_SECTION类型的变量用来扮演红绿灯的角色,让同一个时间内只有一个线程进入临界区。该临界区变量的声明必须是全局的,这样不同的线程就能访问它。操纵临界区的Win32函数初始化和维护该结构中的所有成员,不要自己去访问和修改任何成员。

    使用临界区之前,必须调用InitializeCriticalSection()函数来初始化临界区。而通过调用EnterCriticalSection()函数来取得一个临界区的所有权。然后通过LeaveCriticalSection()函数来释放所有权。临界区通过一个线程取得所有权来显示它已经进入代码临界区的方法进行工作,如果其他线程调用EnterCriticalSection()并引用同一临界区,它会被阻塞,直到第一个线程调用LeaveCriticalSection()函数。最后,可以调用DeleteCriticalSection()函数来释放用户初始化临界区时分配的系统资源。

   
    在MFC中封装了CCriticalSection类作为临界区对象,在构造函数中自动调用InitialCriticalSection()函数,在析构函数中自动调用LeaveCriticalSection()函数,用Lock()和Unlock()对应取得所有权和释放所有权。

 

----------------------------------------------

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <stdlib.h>

#define  threadnum 10

typedef struct THREADDATA
{
   int id;
   char name[10];
   int sleep;
}THREADDATA;

CRITICAL_SECTION sec1;

char * str;

DWORD WINAPI ThreadProc( LPVOID lpParam )
{
   THREADDATA *data=(THREADDATA *)lpParam;
   printf("%d\n%s\n",data->id,data->name);
   EnterCriticalSection(&sec1);
   for(int i=0;i<10;i++)
   {
 //  EnterCriticalSection(&sec1);
   printf("thread%d:%d\n",data->id,i);
 //  LeaveCriticalSection(&sec1);
   Sleep(data->sleep);

   }
   LeaveCriticalSection(&sec1);

   return 0;
}

int main(int argc, char* argv[])
{
   str=(char*)malloc(30);
   THREADDATA  pData[threadnum];
   DWORD dwThreadId[threadnum];
   HANDLE hThread[threadnum];

   InitializeCriticalSection(&sec1);
 
   for(int i=0;i<threadnum;i++)
   {
     pData[i].id=i;
     sprintf(pData[i].name,"yuguoqing");
     pData[i].sleep=i*10;
     hThread[i] = CreateThread(NULL,0,ThreadProc, pData+i, 0,  dwThreadId+i);
   }

    WaitForMultipleObjects(threadnum, hThread, TRUE, INFINITE);

 return 0;
}

转载http://blog.sina.com.cn/s/blog_5040a4e90100gntv.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多