C#中四种进程或线程同步互斥的控制方法

C#中四种进程或线程同步互斥的控制方法
C#中四种进程或线程同步互斥的控制方法

很想整理一下自己对进程线程同步互斥的理解。正巧周六一个刚刚回到学校的同学请客吃饭。在吃饭的过程中,有两个同学,为了一个问题争论的面红耳赤。一个认为.Net下的进程线程控制模型更加合理。一个认为Java下的线程池策略比.Net的好。大家的话题一下转到了进程线程同步互斥的控制问题上。回到家,想了想就写了这个东东。

现在流行的进程线程同步互斥的控制机制,其实是由最原始最基本的4种方法实现的。由这4种方法组合优化就有了.Net和Java下灵活多变的,编程简便的线程进程控制手段。

这4种方法具体定义如下在《操作系统教程》ISBN 7-5053-6193-7 一书中可以找到更加详细的解释

1临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。

2互斥量:为协调共同对一个共享资源的单独访问而设计的。

3信号量:为控制一个具有有限数量用户资源而设计。

4事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。

临界区(Critical Section)

保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。

临界区包含两个操作原语: EnterCriticalSection()进入临界区 LeaveCriticalSection()离开临界区

EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。

MFC提供了很多功能完备的类,我用MFC实现了临界区。MFC为临界区提供有一个CCriticalSection类,使用该类进行线程同步处理是非常简单的。只需在线程函数中用CCriticalSection类成员函数Lock()和UnLock()标定出被保护代码片段即可。Lock()后代码用到的资源自动被视为临界区内的资源被保护。UnLock后别的线程才能访问这些资源。

代码:

//CriticalSection

CCriticalSection global_CriticalSection;

// 共享资源

char global_Array[256];

//初始化共享资源

void InitializeArray()

{

for(int i = 0;i<256;i++)

{

global_Array[i]=I;

}

}

//写线程

UINT Global_ThreadWrite(LPVOID pParam)

{

CEdit *ptr=(CEdit *)pParam;

ptr->SetWindowText("");

//进入临界区

global_CriticalSection.Lock();

for(int i = 0;i<256;i++)

{

global_Array[i]=W;

ptr->SetWindowText(global_Array);

Sleep(10);

}

//离开临界区

global_CriticalSection.Unlock();

return 0;

}

//删除线程

UINT Global_ThreadDelete(LPVOID pParam)

{

CEdit *ptr=(CEdit *)pParam;

ptr->SetWindowText("");

//进入临界区

global_CriticalSection.Lock();

for(int i = 0;i<256;i++)

{

global_Array[i]=D;

ptr->SetWindowText(global_Array);

Sleep(10);

}

//离开临界区

global_CriticalSection.Unlock();

return 0;

}

//创建线程并启动线程

void CCriticalSectionsDlg::OnBnClickedButtonLock()

{

//Start the first Thread

CWinThread *ptrWrite = AfxBeginThread(Global_ThreadWrite, &m_Write,

THREAD_PRIORITY_NORMAL,

0,

CREATE_SUSPENDED);

ptrWrite->ResumeThread();

//Start the second Thread

CWinThread *ptrDelete = AfxBeginThread(Global_ThreadDelete, &m_Delete,

THREAD_PRIORITY_NORMAL,

0,

CREATE_SUSPENDED);

ptrDelete->ResumeThread();

}

在测试程序中,Lock UnLock两个按钮分别实现,在有临界区保护共享资源的执行状态,和没有临界区保护共享资源的执行状态。

互斥量(Mutex)

互斥量跟临界区很相似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。互斥量比临界区复杂。因为使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。

互斥量包含的几个操作原语:

CreateMutex()创建一个互斥量

OpenMutex()打开一个互斥量

ReleaseMutex()释放互斥量

WaitForMultipleObjects()等待互斥量对象

同样MFC为互斥量提供有一个CMutex类。使用CMutex类实现互斥量操作非常简单,但是要特别注意对CMutex 的构造函数的调用

CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL)

不用的参数不能乱填,乱填会出现一些意想不到的运行结果。

代码:

//创建互斥量

CMutex global_Mutex(0,0,0);

// 共享资源

char global_Array[256];

void InitializeArray()

{

for(int i = 0;i<256;i++)

{

global_Array[i]=I;

}

}

UINT Global_ThreadWrite(LPVOID pParam)

{

CEdit *ptr=(CEdit *)pParam;

ptr->SetWindowText("");

global_Mutex.Lock();

for(int i = 0;i<256;i++)

{

global_Array[i]=W;

ptr->SetWindowText(global_Array);

Sleep(10);

}

global_Mutex.Unlock();

return 0;

}

UINT Global_ThreadDelete(LPVOID pParam)

{

CEdit *ptr=(CEdit *)pParam;

ptr->SetWindowText("");

global_Mutex.Lock();

for(int i = 0;i<256;i++)

{

global_Array[i]=D;

ptr->SetWindowText(global_Array);

Sleep(10);

}

global_Mutex.Unlock();

return 0;

}

同样在测试程序中,Lock UnLock两个按钮分别实现,在有互斥量保护共享资源的执行状态,和没有互斥量保护共享资源的执行状态。

信号量(Semaphores)

信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中的PV操作相同。它指出了同时访问共享资源的线程最大数目。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。在用CreateSemaphore()创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就会减1,只要当前可用资源计数是大于0的,就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目,不能在允许其他线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过ReleaseSemaphore()函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。

PV操作及信号量的概念都是由荷兰科学家E.W.Dijkstra提出的。信号量S是一个整数,S大于等于零时代表可供并发进程使用的资源实体数,但S小于零时则表示正在等待使用共享资源的进程数。

P操作申请资源:

(1)S减1;

(2)若S减1后仍大于等于零,则进程继续执行;

(3)若S减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转入进程调度。

V操作释放资源:

(1)S加1;

(2)若相加结果大于零,则进程继续执行;

(3)若相加结果小于等于零,则从该信号的等待队列中唤醒一个等待进程,然后再返回原进程继续执行或转入进程调度。

信号量包含的几个操作原语:

CreateSemaphore()创建一个信号量

OpenSemaphore()打开一个信号量

ReleaseSemaphore()释放信号量

WaitForSingleObject()等待信号量

代码:

//信号量句柄

HANDLE global_Semephore;

// 共享资源

char global_Array[256];

void InitializeArray()

{

for(int i = 0;i<256;i++)

{

global_Array[i]=I;

}

}

//线程1

UINT Global_ThreadOne(LPVOID pParam)

{

CEdit *ptr=(CEdit *)pParam;

ptr->SetWindowText("");

//等待对共享资源请求被通过等于 P操作

WaitForSingleObject(global_Semephore, INFINITE);

for(int i = 0;i<256;i++)

{

global_Array[i]=O;

ptr->SetWindowText(global_Array);

Sleep(10);

}

//释放共享资源等于 V操作

ReleaseSemaphore(global_Semephore, 1, NULL);

return 0;

}

UINT Global_ThreadTwo(LPVOID pParam)

{

CEdit *ptr=(CEdit *)pParam;

ptr->SetWindowText("");

WaitForSingleObject(global_Semephore, INFINITE);

for(int i = 0;i<256;i++)

{

global_Array[i]=T;

ptr->SetWindowText(global_Array);

Sleep(10);

}

ReleaseSemaphore(global_Semephore, 1, NULL);

return 0;

}

UINT Global_ThreadThree(LPVOID pParam)

{

CEdit *ptr=(CEdit *)pParam;

ptr->SetWindowText("");

WaitForSingleObject(global_Semephore, INFINITE);

for(int i = 0;i<256;i++)

{

global_Array[i]=H;

ptr->SetWindowText(global_Array);

Sleep(10);

}

ReleaseSemaphore(global_Semephore, 1, NULL);

return 0;

}

void CSemaphoreDlg::OnBnClickedButtonOne()

{

//设置信号量 1 个资源 1同时只可以有一个线程访问

global_Semephore= CreateSemaphore(NULL, 1, 1, NULL);

this->StartThread();

// TODO: Add your control notification handler code here

}

void CSemaphoreDlg::OnBnClickedButtonTwo()

{

//设置信号量 2 个资源 2 同时只可以有两个线程访问

global_Semephore= CreateSemaphore(NULL, 2, 2, NULL);

this->StartThread();

// TODO: Add your control notification handler code here

}

void CSemaphoreDlg::OnBnClickedButtonThree()

{

//设置信号量 3 个资源 3 同时只可以有三个线程访问

global_Semephore= CreateSemaphore(NULL, 3, 3, NULL);

this->StartThread();

// TODO: Add your control notification handler code here

}

信号量的使用特点使其更适用于对Socket(套接字)程序中线程的同步。例如,网络上的HTTP服务器要对同一时间内访问同一页面的用户数加以限制,这时可以为每一个用户对服务器的页面请求设置一个线程,而页面则是待保护的共享资源,通过使用信号量对线程的同步作用可以确保在任一时刻无论有多少用户对某一页面进行访问,只有不大于设定的最大用户数目的线程能够进行访问,而其他的访问企图则被挂起,只有在有用户退出对此页面的访问后才有可能进入。

事件(Event)

事件对象也可以通过通知操作的方式来保持线程的同步。并且可以实现不同进程中的线程同步操作。

信号量包含的几个操作原语:

CreateEvent()创建一个信号量

OpenEvent()打开一个事件

SetEvent()回置事件

WaitForSingleObject()等待一个事件

WaitForMultipleObjects()等待多个事件

WaitForMultipleObjects 函数原型:

WaitForMultipleObjects(

IN DWORD nCount, // 等待句柄数

IN CONST HANDLE *lpHandles, //指向句柄数组

IN BOOL bWaitAll, //是否完全等待标志

IN DWORD dwMilliseconds //等待时间

参数nCount指定了要等待的内核对象的数目,存放这些内核对象的数组由lpHandles来指向。fWaitAll对指定的这nCount个内核对象的两种等待方式进行了指定,为TRUE时当所有对象都被通知时函数才会返回,为FALSE 则只要其中任何一个得到通知就可以返回。dwMilliseconds在这里的作用与在WaitForSingleObject()中的作用是完全一致的。如果等待超时,函数将返回WAIT_TIMEOUT。

代码:

//事件数组

HANDLE global_Events[2];

// 共享资源

char global_Array[256];

void InitializeArray()

{

for(int i = 0;i<256;i++)

{

global_Array[i]=I;

}

}

UINT Global_ThreadOne(LPVOID pParam)

{

CEdit *ptr=(CEdit *)pParam;

ptr->SetWindowText("");

for(int i = 0;i<256;i++)

{

global_Array[i]=O;

ptr->SetWindowText(global_Array);

Sleep(10);

}

//回置事件

SetEvent(global_Events[0]);

return 0;

}

UINT Global_ThreadTwo(LPVOID pParam)

{

CEdit *ptr=(CEdit *)pParam;

ptr->SetWindowText("");

for(int i = 0;i<256;i++)

{

global_Array[i]=T;

ptr->SetWindowText(global_Array);

Sleep(10);

}

//回置事件

SetEvent(global_Events[1]);

return 0;

}

UINT Global_ThreadThree(LPVOID pParam)

{

CEdit *ptr=(CEdit *)pParam;

ptr->SetWindowText("");

//等待两个事件都被回置

WaitForMultipleObjects(2, global_Events, true, INFINITE);

for(int i = 0;i<256;i++)

{

global_Array[i]=H;

ptr->SetWindowText(global_Array);

Sleep(10);

}

return 0;

}

void CEventDlg::OnBnClickedButtonStart()

{

for (int i = 0; i < 2; i++)

{

//实例化事件

global_Events[i]=CreateEvent(NULL,false,false,NULL);

}

CWinThread *ptrOne = AfxBeginThread(Global_ThreadOne,

&m_One,

THREAD_PRIORITY_NORMAL,

0,

CREATE_SUSPENDED);

ptrOne->ResumeThread();

//Start the second Thread

CWinThread *ptrTwo = AfxBeginThread(Global_ThreadTwo,

&m_Two,

THREAD_PRIORITY_NORMAL,

0,

CREATE_SUSPENDED);

ptrTwo->ResumeThread();

//Start the Third Thread

CWinThread *ptrThree = AfxBeginThread(Global_ThreadThree,

&m_Three,

THREAD_PRIORITY_NORMAL,

0,

CREATE_SUSPENDED);

ptrThree->ResumeThread();

// TODO: Add your control notification handler code here

}

事件可以实现不同进程中的线程同步操作,并且可以方便的实现多个线程的优先比较等待操作,例如写多个WaitForSingleObject来代替WaitForMultipleObjects从而使编程更加灵活。

总结:

1.互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使用。所以创建互斥量需要的资源更多,所以如果只为了在进程内部是用的话使用临界区会带来速度上的优势并能够减少资源占用量。因为互斥量是跨进程的互斥量一旦被创建,就可以通过名字打开它。

2.互斥量(Mutex),信号灯(Semaphore),事件(Event)都可以被跨越进程使用来进行同步数据操作,而其他的对象与数据同步操作无关,但对于进程和线程来讲,如果进程和线程在运行状态则为无信号状态,在退出后为有信号状态。所以可以使用WaitForSingleObject来等待进程和线程退出。

3.通过互斥量可以指定资源被独占的方式使用,但如果有下面一种情况通过互斥量就无法处理,比如现在一位用户购买了一份三个并发访问许可的数据库系统,可以根据用户购买的访问许可数量来决定有多少个线程/进程能同时进行数据库操作,这时候如果利用互斥量就没有办法完成这个要求,信号灯对象可以说是一种资源计数器。

进程同步机制与互斥-生产者消费者问题

学习中心: 专业: 年级:年春/秋季 学号: 学生: 题目:进程同步与互斥生产者-消费者问题 1.谈谈你对本课程学习过程中的心得体会与建议? 转眼间,学习了一个学期的计算机操作系统课程即将结束。在这个学期中,通过老师的悉心教导,让我深切地体会到了计算机操作系统的一些原理和具体操作过程。在学习操作系统之前,我只是很肤浅地认为操作系统只是单纯地讲一些关于计算机方面的操作应用,并不了解其中的具体操作过程 1.1设计思路 在这次设计中定义的多个缓冲区不是环形循环的,并且不需要按序访问。其中生产者可以把产品放到某一个空缓冲区中,消费者只能消费被指定生产者生产的产品。本设计在测试用例文件中指定了所有生产和消费的需求,并规定当共享缓冲区的数据满足了所有有关它的消费需求后,此共享才可以作为空闲空间允许新的生产者使用。

本设计在为生产者分配缓冲区时各生产者之间必须互斥,此后各个生产者的具体生产活动可以并发。而消费者之间只有在对同一个产品进行消费时才需要互斥,它们在消费过程结束时需要判断该消费者对象是否已经消费完毕并释放缓冲区的空间。 1.2程序流程图 1.3基本内容 在设计程序时主要有三个主体部分、三个辅助函数和一个数据结构。 其中主体部分为一个主函数main(),用于初始化缓冲区和各个同步对象,并完成线程信息的读入,最后根据该组的线程记录启动模拟线程,并等待所有线程的运 Y

行结束后退出程序; 生产者函数Produce()和消费者函数Consume(),生产者和消费者函数运行于线程中完成对缓冲区的读、写动作,根据此处生产消费的模型的特点,生产者和消费者之间通过使用同步对象实现了生产和消费的同步与互斥,是本实验的核心所在。 另外三个辅助性函数被生产者和消费者函数调用,是上述生产和消费函数中对缓冲区进行的一系列处理。 3)在实现本程序的消费生产模型时,具体的通过如下同步对象实现互斥: ①设一个互斥量h_mutex,以实现生产者在查询和保留缓冲区内的下一个位置时进行互斥。 ②每一个生产者用一个信号量与其消费者同步,通过设置h_Semaphore[MAX_THREAD_NUM]信号量 ③数组实现,该组信号量用于相应的产品已产生。同时用一个表示空缓冲区

进程间的同步和互斥-

实验报告 1、实验名称 进程间的互斥和同步 2、小组成员:姓名+学号 3、实验目的 Linux命名信号量实现进程间的互斥和同步 4、实验背景知识 进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系来源于他们之间的合作。比如说进程A需要从缓冲区读取进程B产生的信息,当缓冲区为空时,进程B因为读取不到信息而被阻塞。而当进程A产生信息放入缓冲区时,进程B才会被唤醒。 进程互斥是进程之间的间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待。只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。比如进程B需要访问打印机,但此时进程A占有了打印机,进程B会被阻塞,直到进程A释放了打印机资源,进程B才可以继续执行。 5、实验步骤演示 大概步骤: 先进行单次同步,把信号量先初始化为0,创建一个命名信号量,设置信号捕捉处理代码,安装捕捉信号;其次使用信号量进行同步和互斥的操作。 详细步骤: 1.创建一个命名信号量,sem = sem_open(SEM_NAME, OPEN_FLAG, OPEN_MODE, INIT_V); 2.创建子进程,pid = fork(); 3.V操作,sem_post(sem); 4.P操作,sem_wait(sem); 5.等待子进程结束,wait(&status); 6.删掉在系统创建的信号量,sem_unlink(SEM_NAME); 7.彻底销毁打开的信号量,sem_close(sem);

8.信号捕捉处理,static void myhandler(void); 9.迭代同步,两个信号量,开始时一个为1,一个为0,一个进程执行完换另一个执行; 10.安装捕捉信号,signal(SIGINT,(void *)myhandler ); 11.创建一个命名信号量:sem1 = sem_open(SEM_NAME1, OPEN_FLAG, OPEN_MODE, 1);sem2 = sem_open(SEM_NAME2, OPEN_FLAG, OPEN_MODE, 0); 12.创建子进程,pid = fork(); 13.if(0 == pid) P操作:sem_wait(sem1); V操作:sem_post(sem2); 14.if(0 < pid) P操作:sem_wait(sem2); V操作:sem_post(sem1); 15.static void mysem(char *str) { int i = 0; //P操作 sem_wait(sem); while('\0' != str[i]) { printf("%c\n", str[i++]); sleep(1); } //V操作 sem_post(sem); } 进程排斥,在临界区设置PV操作 16.创建一个命名信号量,sem = sem_open(SEM_NAME, OPEN_FLAG, OPEN_MODE, INIT_V); 17.if(0 == pid) { mysem("abcd"); } 18.if(0 < pid) { mysem("1234"); //等待子进程结束 wait(&status); //删掉在系统创建的信号量 sem_unlink(SEM_NAME); //彻底销毁打开的信号量 sem_close(sem); } 说明: 命名信号量不带内存共享,编译时要带库文件-lpthread或-lrt

进程同步与通信作业习题与答案

第三章 一.选择题(50题) 1.以下_B__操作系统中的技术是用来解决进程同步的。 A.管道 B.管程 C.通道 2.以下_B__不是操作系统的进程通信手段。 A.管道 B.原语 C.套接字 D.文件映射 3.如果有3个进程共享同一程序段,而且每次最多允许两个进程进入该程序段,则信号量的初值应设置为_B__。 4.设有4个进程共享一个资源,如果每次只允许一个进程使用该资源,则用P、V操作管理时信号量S的可能取值是_C__。 ,2,1,0,-1 ,1,0,-1,-2 C. 1,0,-1,-2,-3 ,3,2,1,0 5.下面有关进程的描述,是正确的__A__。 A.进程执行的相对速度不能由进程自己来控制 B.进程利用信号量的P、V 操作可以交换大量的信息 C.并发进程在访问共享资源时,不可能出现与时间有关的错误 、V操作不是原语操作 6.信号灯可以用来实现进程之间的_B__。 A.调度 B.同步与互斥 C.同步 D.互斥 7.对于两个并发进程都想进入临界区,设互斥信号量为S,若某时S=0,表示_B__。 A.没有进程进入临界区 B.有1个进程进入了临界区 C. 有2个进程进入了临界区 D. 有1个进程进入了临界区并且另一个进程正等待进入 8. 信箱通信是一种_B__方式 A.直接通信 B.间接通信 C.低级通信 D.信号量 9.以下关于临界区的说法,是正确的_C__。

A.对于临界区,最重要的是判断哪个进程先进入 B.若进程A已进入临界区,而进程B的优先级高于进程A,则进程B可以 打断进程A而自己进入临界区 C. 信号量的初值非负,在其上只能做PV操作 D.两个互斥进程在临界区内,对共享变量的操作是相同的 10. 并发是指_C__。 A.可平行执行的进程 B.可先后执行的进程 C.可同时执行的进程 D.不可中断的进程 11. 临界区是_C__。 A.一个缓冲区 B.一段数据区 C.一段程序 D.栈 12.进程在处理机上执行,它们的关系是_C__。 A.进程之间无关,系统是封闭的 B.进程之间相互依赖相互制约 C.进程之间可能有关,也可能无关 D.以上都不对 13. 在消息缓冲通信中,消息队列是一种__A__资源。 A.临界 B.共享 C.永久 D.可剥夺 14. 以下关于P、V操作的描述正确的是__D_。 A.机器指令 B. 系统调用 C.高级通信原语 D.低级通信原语 15.当对信号量进行V源语操作之后,_C__。 A.当S<0,进程继续执行 B.当S>0,要唤醒一个就绪进程 C. 当S<= 0,要唤醒一个阻塞进程 D. 当S<=0,要唤醒一个就绪 16.对临界区的正确论述是__D_。 A.临界区是指进程中用于实现进程互斥的那段代码 B. 临界区是指进程中用于实现进程同步的那段代码 C. 临界区是指进程中用于实现进程通信的那段代码 D. 临界区是指进程中访问临界资源的那段代码 17. __A__不是进程之间的通信方式。 A.过程调用 B.消息传递 C.共享存储器 D.信箱通信 18. 同步是指进程之间逻辑上的__A__关系。

用信号量实现线程同步与互斥

用信号量实现线程同步与互斥 一、相关Win32 API函数 1、创建线程 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); 函数作用:在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄。 各参数含义: ?lpThreadAttributes:指向一个SECURITY_ATTRIBUTES 结构的指针,该结构决定了线程的安全属性,一般置为NULL; ?dwStackSize:指定了线程的堆栈深度,一般都设置为0; ?lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。 一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc 是线程函数 名;函数名称没有限制,但是必须以下列形式声明:DWORD WINAPI ThreadProc (PVOID pParam) ; ?lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数; ?dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产 生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用; ?lpThreadId:该参数返回所创建线程的ID。 如果创建成功则返回线程的句柄,否则返回NULL。 例如: for (int i=0;i

操作系统 实验 五 线程间的互斥与同步

实验五线程间的互斥与同步 实验学时:2学时 实验类型:验证、设计型 一、实验目的 理解POSIX线程(Pthread)互斥锁和POSIX信号量机制,学习它们的使用方法;编写程序,实现多个POSIX线程的同步控制。 二,实验内容 创建4个POSIX线程。其中2个线程(A和B)分别从2个数据文件(data1.txt和data2.txt)读取10个整数. 线程A和B把从文件中读取的逐一整数放入一个缓冲池. 缓冲池由n个缓冲区构成(n=5,并可以方便地调整为其他值),每个缓冲区可以存放一个整数。另外2个线程,C和D,各从缓冲池读取10数据。线程C、D每读出2个数据,分别求出它们的和或乘积,并打印输出。 提示:在创建4个线程当中,A和B是生产者,负责从文件读取数据到公共的缓冲区,C和D是消费者,从缓冲区读取数据然后作不同的计算(加和乘运算)。使用互斥锁和信号量控制这些线程的同步。不限制线程C和D从缓冲区得到的数据来自哪个文件。 在开始设计和实现之前,务必认真阅读课本6.8.4节和第6章后面的编程项目——生产者-消费者问题。

三,实验要求 按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。 四,实验设计 1,功能设计 根据实验要求,主程序需要创建四个线程,两个线程负责从文件读取数据到缓冲区,两个线程负责将缓冲区的数据做数学运算。由于同一个进程中的各个线程共享资源,可以用一个二维数组的全局变量作为公共缓冲区,同时还需要一个整形全局变量size用来做数组的索引。读线程的运行函数打开不同的文件并从中读取数据到二维数组中,每次写入数组后size加一。运算线程从二维数组中读数并做运算,每次读数之前size减一。本题的关键在于如何使用信号量保证进程的同步与互斥。在运算线程从缓冲区读取之前缓冲区里必须有数,即任意时刻运算操作的执行次数必须小于等于读取操作的执行次数。同时应该保证两个读线程和两个运算线程两两互斥。由于以上分析,使用了四个信号量sem1,sem2,sem3和sem4。sem1保证线程1和线程2互斥,sem2保证线程3和线程4互斥,sem3保证线程3和线程4互斥,sem4保证线程4和线程1互斥。即这四个信号量使四个线程循环进行,从而保证了运行结果的正确性。 源代码及注释: #include #include #include #define NUM 200

进程同步互斥1

进程的同步互斥实验 实验目的 1、进一步认识并发执行的实质 2、分析进程竞争资源的现象,学习解决进程同步互斥的方法 实验内容 1、编写程序,使用相关函数实现父子进程对共享文件的同步互斥访问。 2、修改程序,观察对临界资源访问的互斥控制的作用。 实验基础 一、临界资源的互斥访问 为了实现多进程对临界资源的互斥访问,一个进程访问临界资源的典型程序段类似如下形式: { ………. 进入区 临界区; 退出区 其余代码; ………} 其中,进入区中判断资源是否可用,如果可用,则资源数量减1,进程进入临界区;否则进程阻塞等待。退出区中资源数量加1,唤醒阻塞等待该资源的进程。进入区和退出区都是原子操作。 操作系统中,通常用信号量来实现进入区和退出区,即P操作和V操作。为了实现用户程序中对某些资源的同步互斥访问,操作系统也提供了一些函数接口,功能类似于对特定临界区的进入区和退出区功能。 二、相关的系统调用 (1)lockf(files,function,size) :用作锁定文件的某些段或者整个文件。 函数原型: #include int lockf(int files,int function;long size) 其中:files是文件描述符;参数function可以取以下值:F_LOCK:锁定一个区域。F_ULOCK:解除锁定。参数size指明了从文件当前位置开始的一段连续锁定区域的长度,当size为0时,锁定记录将由当前位置一直扩展到文件尾。 如果lockf的参数function取值为F_LOCK,而指定文件的对应区域已被其他进程锁定,

那么lockf的调用进程将被阻塞直到该区域解锁。 通过使用lockf函数,可实现多进程对共享文件进行互斥访问。进程的实现中,必须使得每个进程在使用文件前对文件加锁,使用文件后解锁。 (2)open:打开一个文件 函数原型:#include #include #include int open(char *path,int flags,mode_t mode); 其中:参数path 是指向所要打开的文件的路径名指针。 参数falgs 规定如何打开该文件,它必须包含以下值之一:O_RDONL Y,只读打开;O_WRONL Y,只写打开;O_RDWR,读/写打开;O_CREAT,当文件不存在时创建文件,需参数mode;O_APPEND,不论当前文件位置在何处,将文件指针移至文件尾,为write添加数据到文件;O_TRUNC,当以可写的方式成功打开普通文件时,截断该文件的长度为0。 参数mode 规定对该文件的访问权限。 open系统调用可以只使用前面介绍的这两个参数,省略第三个参数mode。第三个参数是在用O_CREAT创建文件时使用,指出新建文件的存取许可权。由这个参数指出的存取许可权还要和umask进行运算后才得到新建文件的真正存取许可权。该运算是由umask按位取反,再按位与上第三个参数给出的数取或(~umask&mode)。例如:umask为022,mode为0770,则新建文件的存取许可权为0750即-rwxr-x---。 (3)read:读文件 函数原型:#include int read(int fd,void *buf,size_t nbytes) 该系统调用从文件描述符fd所代表的文件中读取nbytes 个字节,到buf指定的缓冲区内。所读取的内容从当前的读/写指针所指示的位置开始,这个位置由相应的打开文件描述中的偏移值(off_set)给出,调用成功后文件读写指针增加实际读取的字节数。 使用read 系统调用时,应注意设置的数据缓冲区充分大,能够存放所要求的数据字节,因为内核只复制数据,不进行检查。 返回:-1:错误;0:文件偏移值是在文件结束处;整数:从该文件复制到规定的缓冲区中的字节数。通常这个字节数与所请求的字节数相同。除非请求的字节数超过剩余的字节数,这时将返回一个小于请求的字节数的数字。 (4)write:写文件 函数原型:#include int write(int fd,void *buf,size_t nbytes) 该调用从buf所指的缓冲区中将nbytes 个字节写到描述符fd所指的文件中。 (5)lseek:定位一个已打开文件。 函数原型:#include int lseek(int fildes,off_t offset,int whence); 系统调用根据whence指定的位置将文件描述符fildes指向文件的文件指针偏移offset

操作系统实验-进程同步与互斥

实验四:进程的管道通信 实验题目 进程的管道通信 实验目的 加深对进程概念的理解,明确进程和程序的区别。学习进程创建的过程,进一步认识进程并发执行的实质。分析进程争用资源的现象,学习解决进程互斥的方法。学习解决进程同步的方法。掌握Linux系统中进程间通过管道通信的具体实现 实验内容 使用系统调用pipe()建立一条管道,系统调用fork()分别创建两个子进程,它们分别向管道写一句话,如: Child process1 is sending a message! Child process2 is sending a message! 父进程分别从管道读出来自两个子进程的信息,显示在屏幕上。 当然,仅仅通过屏幕上输出这两句话还不能说明实现了进程的管道通信,为了能够更好的证明和显示出进程的同步互斥和通信,在其中要加入必要的跟踪条件,如一定的输出语句等,来反映程序的并发执行情况 实验要求 这是一个设计型实验,要求自行、独立编制程序。两个子进程要并发执行。实现管道的互斥使用。当一个子进程正在对管道进行写操

作时,另一个欲写入管道的子进程必须等待。使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定。实现父子进程的同步,当父进程试图从一空管道中读取数据时,便进入等待状态,直到子进程将数据写入管道返回后,才将其唤醒。 为了清楚的反应进程的同步,在子进程完成相应的操作后,调用sleep()函数睡眠一段时间(程序中定为3s)。父进程先执行wait()函数,当有子进程执行完毕后,会得到子进程的返回结果并清理子进程。若子进程没执行完,父进程一直执行wait()进行监听,知道有一个子进程执行完成为僵尸进程。 程序中用到的系统调用 因为程序时在linux系统上进行编写的,所以其中要利用到相关的linux提供的系统调用。 所用到的系统调用包含在如下头文件中。 #include #include #include #include #include #include fork() 用于创一个子进程。 格式:int fork();

四种进程或线程同步互斥的控制方法

四种进程或线程同步互斥的控制方法 1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。 2、互斥量:为协调共同对一个共享资源的单独访问而设计的。 3、信号量:为控制一个具有有限数量用户资源而设计。 4、事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。 一临界区 临界区的使用在线程同步中应该算是比较简单,说它简单还是说它同后面讲到的其它方法相比更容易理解。举个简单的例子:比如说有一个全局变量(公共资源)两个线程都会对它进行写操作和读操作,如果我们在这里不加以控制,会产生意想不到的结果。假设线程A 正在把全局变量加1然后打印在屏幕上,但是这时切换到线程B,线程B又把全局变量加1然后又切换到线程A,这时候线程A打印的结果就不是程序想要的结果,也就产生了错误。解决的办法就是设置一个区域,让线程A在操纵全局变量的时候进行加锁,线程B如果想操纵这个全局变量就要等待线程A释放这个锁,这个也就是临界区的概念。 二互斥体 windows api中提供了一个互斥体,功能上要比临界区强大。也许你要问,这个东东和临界区有什么区别,为什么强大?它们有以下几点不一致: 1.critical section是局部对象,而mutex是核心对象。因此像waitforsingleobject是不可以等待临界区的。 2.critical section是快速高效的,而mutex同其相比要慢很多 3.critical section使用围是单一进程中的各个线程,而mutex由于可以有一个名字,因此它是可以应用于不同的进程,当然也可以应用于同一个进程中的不同线程。 4.critical section 无法检测到是否被某一个线程释放,而mutex在某一个线程结束之后会产生一个abandoned的信息。同时mutex只能被拥有它的线程释放。下面举两个应用mutex 的例子,一个是程序只能运行一个实例,也就是说同一个程序如果已经运行了,就不能再运行了;另一个是关于非常经典的哲学家吃饭问题的例子。 三事件 事件对象的特点是它可以应用在重叠I/O(overlapped I/0)上,比如说socket编程中有两种模型,一种是重叠I/0,一种是完成端口都是可以使用事件同步。它也是核心对象,因此可以被waitforsingleobje这些函数等待;事件可以有名字,因此可以被其他进程开启。 四信号量 semaphore的概念理解起来可能要比mutex还难,我先简单说一下创建信号量的函数,因为我在开始使用的时候没有很快弄清楚,可能现在还有理解不对的地方,如果有错误还是请大侠多多指教。 CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD LONG lInitialCount, // initial count LONG lMaximumCount, // maximum count LPCTSTR lpName // object name )

计算机操作系统_进程间互斥与同步

进程间互斥与同步 实验内容: 编写算法,实现进程间对临界资源的互斥访问以及进程间的同步关系。 实验要求: 1、要求进程互斥使用文本文件; 2、假定文本文件txt1最大可写入30个字符; 3、写满后复制进程将文本文件的内容复制到另一个文本文件txt2中(无长度限制)。 4、复制进程复制完毕写入进程可再重新写入,重复执行3,4,直到给出停止命令。 5、实现进程间的同步和互斥。 代码: #include #include//stdio.h #include//函数库 #include//linux/unix的系统调用 #include//信号量 #include using namespace std; typedef union _semnu{ int val; struct semid_ds *buf; ushort *array; }semun; //v操作 void v(int &sem_id) { struct sembuf sem_b;

sem_b.sem_num=0; sem_b.sem_op=1; sem_b.sem_flg=SEM_UNDO; if(semop(sem_id,&sem_b,1)==-1) { cout<<"error"<

进程同步与互斥汇总

进程同步与互斥

进程的PV操作 在操作系统中,P、V操作是进程管理中的难点。这是1968年荷兰人Dijkstra 给出的一种解决并发进程间互斥和同步关系的通用方法。 1. P、V操作的意义 定义了信号量及其上的P操作和V操作,来实现并发进程间的同步和互斥,甚至可以用来管理资源的分配。P、V操作因交换的信息量少,属于进程的低级通信。 2. 什么是信号量? 信号量(semaphore)是由一个值和一个指针构成的数据结构。值为整型变

量,表示信息量的值;指针指向进程控制块(PCB)队列的队头,表示等待该信号量的下一个进程。如下图所示。 信号量的一般结构及PCB队列 信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的初值不能为负,且其值只能由P、V操作来改变。 3. P、V操作的含义 P、V操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量S进行操作,具体定义如下: P(S): ①将信号量S的值减1,即S=S-1; ②如果S≥0,则该进程继续执行;否则该进程状态置为阻塞状态,进程PCB 排入信号量PCB队列末尾,放弃CPU,等待V操作的执行。 V(S): ①将信号量S的值加1,即S=S+1; ②如果S≤0,释放信号量队列中第一个PCB所对应的进程,将进程状态由阻塞态改为就绪态。执行V操作的进程继续执行。 一般来说,信号量S≥0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S≤0,表示有某些进程正在等待该资源,因此要唤醒一个阻塞状态的进程,使之成为就绪状态。 4. 利用信号量和P、V操作实现进程互斥 一般地,n个进程利用信号量和P、V操作实现进程互斥的一般模型如下: 进程P 1进程P 2 ……进程Pn …… …… …… P(S); P(S); P(S); 临界区;临界区;临界区; V(S); V(S); V(S); …… …… …… …… 其中S是互斥信号量,初值为1。 使用P、V操作实现进程互斥时应该注意的问题是: (1)每个程序中,用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查P、V操作的成对性。 (2)P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。 (3)互斥信号量的初值一般为1。 由于用于互斥的信号量sem与所有的并发进程有关,所以称之为公有信号量。公有信号量的值反映了公有资源的数量。只要把临界区置于P(sem)和V(sem)

进程(线程)的同步与互斥实验报告

操作系统实验报告 课程名称操作系统实验名称进程(线程)的同步与互斥成绩 学生姓名作业君专业软件工程班级、学号 同组者姓名无实验日期2020 一、实验题目:进程(线程)的同步与互斥 二、实验目的: 自行编制模拟程序,通过形象化的状态显示,加深理解进程的概念、进程之间的状态转换及其所带来的PCB内容、组织的变化,理解进程与其PCB间的一一对应关系。1.掌握基本的同步与互斥算法,理解生产者消费者模型。 2.学习使用Windows中基本的同步对象,掌握相关API的使用方法。 3.了解Windows中多线程的并发执行机制,实现进程的同步与互斥 三、实验内容与要求: 1.实验内容 以生产者/消费者模型为依据,在Windows 环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。 2.实验要求 学习并理解生产者/消费者模型及其同步/互斥规则; 学习了解Windows同步对象及其特性; 熟悉实验环境,掌握相关API的使用方法; 设计程序,实现生产者/消费者进程(线程)的同步与互斥; 四、算法描述(含数据结构定义)或流程图 #include #include #include #include #include #include using namespace std;

#define MAX_THREAD_NUM 64 //最大线程数 #define INTE_PER_SEC 1000 //延迟时间的毫秒值 const int SIZE_OF_BUFFER = 10; //缓冲区长度 int ProductID = 0; //产品号 int ConsumeID = 0; //将被消耗的产品号 int in = 0; //产品进缓冲区时的缓冲区下标 int out = 0; //产品出缓冲区时的缓冲区下标 bool running = true; //判断程序能否继续执行的逻辑值 int g_buffer[SIZE_OF_BUFFER]; //缓冲区是个循环队列 HANDLE g_hMutex; //公有信号量,用于线程间的互斥HANDLE g_hFullSemaphore; //生产者的私有信号量,当缓冲区满时迫使生产者等待 HANDLE g_hEmptySemaphore; //消费者的私有信号量,当缓冲区空时迫使消费者等待 //定义一个结构体用于存储线程的信息 struct ThreadInfo { int serial; //线程号 char entity; //线程类别(生产者或消费者) double delay; //等待时间 double persist; //操作时间 }; //生产者 void Producer(void* p) { //定义变量用于存储当前线程的信息 DWORD m_delay; DWORD m_persist; int m_serial; //从参数中获得信息 m_serial = ((ThreadInfo*)(p))->serial; m_delay = (DWORD)(((ThreadInfo*)(p))->delay * INTE_PER_SEC); m_persist = (DWORD)(((ThreadInfo*)(p))->persist * INTE_PER_SEC); while (running) { //P操作 cout << "生产者线程 " << m_serial << " 请求生产." << endl; WaitForSingleObject(g_hEmptySemaphore, INFINITE);

实验1编程实现进程(线程)同步和互斥

实验1编程实现进程(线程)同步和互斥 一、实验目的 ①通过编写程序实现进程同步和互斥,使学生掌握有关进程(线程)同步与 互斥的原理,以及解决进程(线程)同步和互斥的算法,从而进一步巩固进程(线程)同步和互斥 ②等有关的内容。 ③了解Windows2000/XP中多线程的并发执行机制,线程间的同步和互斥。 ④学习使用Windows2000/XP中基本的同步对象,掌握相应的 ⑤API函数。 ⑥掌握进程和线程的概念,进程(线程)的控制原语或系统调用的使用。 ⑦掌握多道程序设计的基本理论、方法和技术,培养学生多道程序设计的能 力。 二、实验内容 在Windows XP、Windows 2000等操作系统下,使用的VC、VB、java或C 等编程语言,采用进程(线程)同步和互斥的技术编写程序实现生产者消费者问题或哲学家进餐问题或读者-写者问题或自己设计一个简单进程(线程)同步和互斥的实际问题。 三、实验要求 ①经调试后程序能够正常运行。 ②采用多进程或多线程方式运行,体现了进程(线程)同步和互斥的关系。 ③程序界面美观。 四、实验步骤、过程 让写者与读者、读者与读者之间互斥的访问同一数据集,在无写者进程到来时各读者可同时的访问数据集,在读者和写者同时等待时写者优先唤醒。设置两个全局变量readcount 和writecount来记录读者与写者的数目,设置了3个信号量。h_mutex1表示互斥对象对阻塞在read这一个过程实现互斥,h_mutex2实现全局变量readcount操作上的互斥,h_mutex3实现对全局变量writecount的互斥访问。设置了两个临界区,为了实现写者优先,用了临界区read。数据结构:(1)用了两个临界区(2)自定义结构ThreadInfo记录一条线程信息,多个线程对应一个ThreadInfo数组。(3)设置了互斥量h_mutex1,实现了互斥对象对阻

Windows下进程同步与互斥

实验进程同步与互斥 一、实验目的 1.掌握基本的同步与互斥算法,理解生产者消费者模型。 2.学习使用Windows 2000/XP中基本的同步对象,掌握相关API的使用方法。 3.了解Windows 2000/XP中多线程的并发执行机制,实现进程的同步与互斥。 二、实验内容及要求 1.实验内容 以生产者/消费者模型为依据,在Windows 2000环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。 2.实验要求 ●学习并理解生产者/消费者模型及其同步/互斥规则; ●学习了解Windows同步对象及其特性; ●熟悉实验环境,掌握相关API的使用方法; ●设计程序,实现生产者/消费者进程(线程)的同步与互斥; ●提交实验报告。 三、相关知识介绍 1.同步对象 同步对象是指Windows中用于实现同步与互斥的实体,包括信号量(Semaphore)、互斥量(Mutex)、临界区(Critical Section)和事件(Events)等。本实验中使用到信号量、互斥量和临界区三个同步对象。 同步对象的使用步骤: ●创建/初始化同步对象。 ●请求同步对象,进入临界区(互斥量上锁)。 ●释放同步对象(互斥量解锁)。 这些对象在一个线程中创建,在其他线程中都可以使用,实现同步与互斥。 2.相关API的功能及使用 我们利用Windows SDK提供的API编程实现实验题目要求,而VC中包含有Windows SDK的所有工具和定义。要使用这些API,需要包含堆这些函数进行说明的SDK头文件——最常见的是Windows.h(特殊的API调用还需要包含其他头文件)。 下面给出的是本实验使用到的API的功能和使用方法简单介绍。 (1) CreateThread ●功能——创建一个在调用进程的地址空间中执行的线程 ●格式 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,

多线程同步方法及比较

多线程同步方法及比较 多线程同步方法: 1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数 据访问。. 2.互斥量:为协调一起对一个共享资源的单独访问而设计的。. 3.信号量:为控制一个具备有限数量用户资源而设计。. 4.事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。 临界区(Critical Section).. 确保在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。假如有多个线程试图同时访问临界区,那么在有一个线程进入后其他任何试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程能够继续抢占,并以此达到用原子方式操作共享资源的目的。 临界区包含两个操作原语: EnterCriticalSection()进入临界区 LeaveCriticalSection()离开临界区。 EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保和之匹配的LeaveCriticalSection()都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。 MFC为临界区提供有一个CCriticalSection类,使用该类进行线程同步处理是很简单的。只需在线程函数中用CCriticalSection类成员函数Lock()和UnLock()标定出被保护代码片段即可。Lock()后代码用到的资源自动被视为临界区内的资源被保护。UnLock后别的线程才能访问这些资源。. ------------------------------------------------

实验一 进程同步与互斥

实验一进程同步与互斥 一、实验目的 1.掌握基本的同步与互斥算法,理解生产者消费者模型。 2.学习使用Windows 2000/XP中基本的同步对象,掌握相关API的使用方法。 3.了解Windows 2000/XP中多线程的并发执行机制,实现进程的同步与互斥。 二、实验内容及要求 1.实验内容 以生产者/消费者模型为依据,在Windows 2000环境下创建一个控制台进程,在该进程 中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。 2.实验要求 , 学习并理解生产者/消费者模型及其同步/互斥规则; , 学习了解Windows同步对象及其特性; , 熟悉实验环境,掌握相关API的使用方法; , 设计程序,实现生产者/消费者进程(线程)的同步与互斥; , 提交实验报告。 三、相关知识介绍 1.同步对象 同步对象是指Windows中用于实现同步与互斥的实体,包括信号量(Semaphore)、互斥量(Mutex)、临界区(Critical Section)和事件(Events)等。本实验中使用到信号量、互斥量和临

界区三个同步对象。 同步对象的使用步骤: , 创建/初始化同步对象。 , 请求同步对象,进入临界区(互斥量上锁)。 , 释放同步对象(互斥量解锁)。 这些对象在一个线程中创建,在其他线程中都可以使用,实现同步与互斥。 2.相关API的功能及使用 我们利用Windows SDK提供的API编程实现实验题目要求,而VC中包含有Windows SDK的所有工具和定义。要使用这些API,需要包含堆这些函数进行说明的SDK头文件——最常见的是Windows.h(特殊的API调用还需要包含其他头文件)。 下面给出的是本实验使用到的API的功能和使用方法简单介绍。 (1) CreateThread , 功能——创建一个在调用进程的地址空间中执行的线程 , 格式 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParamiter, DWORD dwCreationFlags, Lpdword lpThread ); , 参数说明 lpThreadAttributes——指向一个LPSECURITY_ATTRIBUTES(新线程的安全性描述符)。

同步和互斥的区别_

同步和互斥的区别

信号量互斥量条件变量 同步和互斥 一、信号量:用于进程间通信(linux中用于线程) 独立于进程在两个进程中都要初始化,若一个已创建,则另一个获取可以执行多次v操作,然后再执行p操作 信号量的一些概念: 以下是信号灯(量)的一些概念: 信号灯与互斥锁和条件变量的主要不同在于”灯”的概念,灯亮则意味着资源可用,灯灭则意味着不可用。如果说后两中同步方式侧重于”等待”操作,即资源不可用的话,信号灯机制则侧重于点灯,即告知资源可用;没有等待线程的解锁或激发条件都是没有意义的,而没有等待灯亮的线程的点灯操作则有效,且能保持灯亮状态。当然,这样的操作原语也意味着更多的开销。 信号灯的应用除了灯亮/灯灭这种二元灯以外,也可以采用大于1的灯数,以表示资源数大于1,这时可以称之为多元灯。 二、互斥量:(用于在线程间的通信) 1、在一个进程中创建 三、信号量与互斥量的区别 1. 互斥量用于线程的互斥,信号量用于线程的同步。 这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源 以上区别是主要想记住的。 note:信号量可以用来实现互斥量的功能 2. 互斥量值只能为0/1,信号量值可以为非负整数。 也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也可以完成一个资源的互斥访问。3、互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到。 4、作用域 信号量: 进程间或线程间(linux仅线程间) 互斥锁: 线程间 5、上锁时 信号量: 只要信号量的value大于0,其他线程就可以sem_wait(p操作-1)成功,成功后信号量的value减一。若value值不大于0,则

相关文档
最新文档