线程的同步与互斥

来源:互联网 发布:java监控服务状态 编辑:程序博客网 时间:2024/05/02 04:56

线程的同步与互斥

  • 线程的同步与互斥
    • mutex (互斥量)

每个线程专属的私有空间,其中上下文信息栈私有空间很是重要。

当多个线程在进程中运行时,他们看到同一份地址空间,这使得线程之间很容易的看到一份公共资源(临界资源),当多个线程看到同一份资源并对这份公共资源进行读写时,我们希望这份资源是原子性的,即我在使用这份资源时我不希望有其他执行流同时对这份资源进行读写操作。这就是为什么要引入线程的同步与互斥的原因。

mutex (互斥量)

多个线程同时访问共享数据时可能会冲突,例如 两个线程都要把某个全局变量增加1,这个操作在某平台需要三条指令完成:

  1. 从内存读变量值到寄存器
  2. 寄存器的值加1
  3. 将寄存器的值写回内存

假设两个线程在多处理器平台上同时执行这三条指令,则可能会导致错误的结果,比如说以下这种情况:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int g_val;
int g_val;
void* thread_val(void* arg)
{
int i = 0;
while (i < 500000)
{
int tmp = g_val;
g_val = tmp + 1;
//printf("%d\n",g_val);
i++;
}
}
int main()
{
pthread_t id1, id2;
pthread_create(&id1, NULL, thread_val, NULL);
pthread_create(&id2, NULL, thread_val, NULL);

pthread_join(id1, NULL);
pthread_join(id2, NULL);
printf("%d\n",g_val);
return 0;
}

我们想要的结果是线程1和线程2在运行完之后将g_val的值加到一百万。实现结果:

pthread1

但明显并不能为什么呢

线程1刚把g_val从内存中取出来,准备对其运算,这时切换到另线程2,线程1会将g_val保存在他的上下文信息中(每个线程有自己私有的上下文信息),回到线程2,如果他将g_val又从内存中取出来,在CPU上经过各种运算再把它放回内存。这时切换回线程1,因为线程一从CPU拿出来的变量保存在他的上下文信息中,所以在g_val被线程2改变后,线程1保存在上下文中的g_val并没有改变,线程1把g_val放入CPU,经过各种运算放回内存,这时线程2的工作就会被线程1覆盖。我们并不希望这样

对于多线程的程序,访问冲突的问题是很普遍的,解决的办法是引入互斥锁(Mutex,Mutual Exclusive Lock),获得锁的线程可以完成“读-修改-写”的操作,然后释放锁给其它线程,没有获得 
锁的线程只能等待而不能访问共享数据,这样“读-修改-写”三步操作组成一个原子操作,要么都执行,要么都不执行,不会执行到中间被打断,也不会在其它处理器上并行做这个操作。

返回值:成功返回0,失败返回错误号。 
pthread_mutex_init函数对Mutex做初始化,参数attr设定Mutex的属性,如果attr为NULL则表示缺省属性。 
pthread_mutex_init函 数初始化的Mutex可以用pthread_mutex_destroy销毁。如果Mutex变量是静态分配的(全局变量 或static变量),也可以用宏定义PTHREAD_MUTEX_INITIALIZER

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int g_val;
void* thread_val(void* arg)
{
int i = 0;
while (i < 500000)
{
pthread_mutex_lock(&lock);//lock here
int tmp = g_val;
g_val = tmp + 1;
//printf("%d\n",g_val);
pthread_mutex_unlock(&lock);//unlock here
i++;
}
}
int main()
{
pthread_t id1, id2;
pthread_create(&id1, NULL, thread_val, NULL);
pthread_create(&id2, NULL, thread_val, NULL);

pthread_join(id1, NULL);
pthread_join(id2, NULL);
pthread_mutex_destroy(&lock);//destroy lock
printf("%d\n",g_val);
return 0;
}

运行结果

pthread2

原创粉丝点击