码迷,mamicode.com
首页 > 编程语言 > 详细

线程同步方式比较

时间:2016-08-13 22:23:29      阅读:190      评论:0      收藏:0      [点我收藏+]

标签:

用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。

内核模式下的方法有:事件,信号量,互斥量。

临界区

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

互斥量 Mutex

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

信号量 

信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源 ,这与操作系统中的PV操作相同。

事件(Event) 

事件机制,则允许一个线程在处理完一个任务后,主动唤醒另外一个线程执行任务。

 

以上几种方法在win和linux下的API又有不同

Linux下实现同步的API:

互斥量 Mutex

  1. 初始化锁。在Linux下,线程的互斥量数据类型是pthread_mutex_t。在使用前,要对它进行初始化。
    静态分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    动态分配:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
  2. 加锁。对共享资源的访问,要对互斥量进行加锁,如果互斥量已经上了锁,调用线程会阻塞,直到互斥量被解锁。
    int pthread_mutex_lock(pthread_mutex *mutex);
    int pthread_mutex_trylock(pthread_mutex_t *mutex);
  3. 解锁。在完成了对共享资源的访问后,要对互斥量进行解锁。
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
  4. 销毁锁。锁在是使用完成后,需要进行销毁以释放资源。
    int pthread_mutex_destroy(pthread_mutex *mutex);

信号量(sem)

如同进程一样,线程也可以通过信号量来实现通信,虽然是轻量级的。信号量函数的名字都以"sem_"打头。线程使用的基本信号量函数有四个。

  1. 信号量初始化。
    int sem_init (sem_t *sem , int pshared, unsigned int value);
    这是对由sem指定的信号量进行初始化,设置好它的共享选项(linux 只支持为0,即表示它是当前进程的局部信号量),然后给它一个初始值VALUE。
  2. 等待信号量。给信号量减1,然后等待直到信号量的值大于0。
    int sem_wait(sem_t *sem);
  3. 释放信号量。信号量值加1。并通知其他等待线程。
    int sem_post(sem_t *sem);
  4. 销毁信号量。我们用完信号量后都它进行清理。归还占有的一切资源。
    int sem_destroy(sem_t *sem);

条件变量(cond) 

互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。条件变量分为两部分: 条件和变量。条件本身是由互斥量保护的。线程在改变条件状态前先要锁住互斥量。条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。条件的检测是在互斥锁的保护下进行的。如果一个条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件,它发信号给关联的条件变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件。如果两进程共享可读写的内存,条件变量可以被用来实现这两进程间的线程同步。

  1. 初始化条件变量。
    静态态初始化,pthread_cond_t cond = PTHREAD_COND_INITIALIER;
    动态初始化,int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
  2. 等待条件成立。释放锁,同时阻塞等待条件变量为真才行。timewait()设置等待时间,仍未signal,返回ETIMEOUT(加锁保证只有一个线程wait)
    int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
    int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
  3. 激活条件变量。pthread_cond_signal,pthread_cond_broadcast(激活所有等待线程)
    int pthread_cond_signal(pthread_cond_t *cond);
    int pthread_cond_broadcast(pthread_cond_t *cond); //解除所有线程的阻塞
  4. 清除条件变量。无线程等待,否则返回EBUSY
    int pthread_cond_destroy(pthread_cond_t *cond);

参考  Linux 线程同步的三种方法

win下实现同步的API:

临界区(Critical Section)

EnterCriticalSection() 进入临界区

LeaveCriticalSection() 离开临界区

互斥量(Mutex) 

CreateMutex() 创建一个互斥量 

OpenMutex() 打开一个互斥量 

ReleaseMutex() 释放互斥量 

WaitForMultipleObjects() 等待互斥量对象 

信号量(Semaphores)

CreateSemaphore() 创建一个信号量

OpenSemaphore() 打开一个信号量

ReleaseSemaphore() 释放信号量

WaitForSingleObject() 等待信号量

事件(Event)

CreateEvent() 创建一个事件 

OpenEvent() 打开一个事件

SetEvent() 回置事件

WaitForSingleObject() 等待一个事件

WaitForMultipleObjects()   等待多个事件

win下互斥量和临界区区别 

 

 

Mutex

Critical Section

性能和速度

慢。

Mutex 是内核对象,相关函数的执行 (WaitForSingleObject,

ReleaseMutex)需要用户模式(User Mode)到内核模式

(Kernel Mode)的转换,在x86处理器上这种转化一般要

发费600个左右的 CPU指令周期。

快。

Critical Section本身不是内核对象,相关函数

(EnterCriticalSection,LeaveCriticalSection)

的调用一般都在用户模式内执行,在x86处理器上

一般只需要发费9个左右的 CPU指令周期。只有

当想要获得的锁正好被别的线程拥有时才会退化

成和Mutex一样,即转换到内核模式,发费600个

左右的 CPU指令周期。

能否跨越进程(Process)边界

可以

不可

定义写法

HANDLE hmtx;

CRITICAL_SECTION cs;

初始化写法

hmtx= CreateMutex (NULL, FALSE, NULL);

InitializeCriticalSection(&cs);

结束清除写法

CloseHandle(hmtx);

DeleteCriticalSection(&cs);

无限期等待的写法

WaitForSingleObject (hmtx, INFINITE);

EnterCriticalSection(&cs);

0等待(状态检测)的写法

WaitForSingleObject (hmtx, 0);

TryEnterCriticalSection(&cs);

任意时间等待的写法

WaitForSingleObject (hmtx, dwMilliseconds);

不支持

锁释放的写法

ReleaseMutex(hmtx);

LeaveCriticalSection(&cs);

能否被一道用于等待其他内核对象

可以(使用WaitForMultipleObjects,

WaitForMultipleObjectsEx,

MsgWaitForMultipleObjects,

MsgWaitForMultipleObjectsEx等等)

不可

当拥有锁的线程死亡时

Mutex变成abandoned状态,其他的等待线程可以获得锁。

Critical Section的状态不可知(undefined),

以后的动作就不能保证了。

自己会不会锁住自己

不会(对已获得的Mutex,重复调用WaitForSingleObject不会

锁住自己。但最后你别忘了要调用同样次数的

ReleaseMutex)

不会(对已获得的Critical Section,重复调用

EnterCriticalSection不会锁住自己。但最后

你别忘了要调用同样次数的

LeaveCriticalSection)

线程同步方式比较

标签:

原文地址:http://www.cnblogs.com/raichen/p/5768752.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!