1线程同步:互斥量,死锁



1 线程为什么要同步

A: 共享资源,多个线程都可对共享资源操作。

B: 线程操作共享资源的先后顺序不确定。

C: 处理器对存储器的操作一般不是原子操作。

2 互斥量

mutex 操作原语

pthread_mutex_t

pthread_mutex_init

pthread_mutex_destroy

pthread_mutex_lock

pthread_mutex_trylock

pthread_mutex_unlock

3 临界区( Critical Section

保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共

享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释

放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。

4 临界区的选定

    临界区的选定因尽可能小,如果选定太大会影响程序的并行处理性能。

5 互斥量实例

依赖的头文件

#include<pthread.h>

函数声明

int pthread_mutex_destroy(pthread_mutex_t*mutex);

pthread_mutex_destroy

释放对互斥变量分配的资源

头文件:

#include <pthread.h>

函数原形:

int  pthread_mutex_destroy(pthread_mutex_t *mutex);

返回值:

若成功则返回 0 ,否则返回错误编号。

 

int pthread_mutex_init(pthread_mutex_t*restrict mutex, const pthread_mutexattr_t *restrict attr);

pthread_mutexattr_init

初始化互斥锁。

头文件:

#include <pthread.h>

函数原形:

int pthread_mutex_init(pthread_mutex_t * mutex,

const pthread_mutex_t *attr);

mutex  互斥量

attr     互斥锁属性

返回值:

若成功则返回 0 ,否则返回错误编号。

int pthread_mutex_lock(pthread_mutex_t*mutex);

int pthread_mutex_trylock(pthread_mutex_t*mutex);

int pthread_mutex_unlock(pthread_mutex_t*mutex);

pthread_mutex_lock/ pthread_mutex_trylock/ pthread_mutex_unlock

对互斥量加 / 减锁

头文件:

#include <pthread.h>

函数原形:

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

返回值:

若成功则返回 0 ,否则返回错误编号。

函数说明:

对互斥量进行加锁,需要调用 pthread_mutex_lock, 如果互斥量已经上锁,调用线程阻塞直至互斥量解锁。对互斥量解锁,需要调用 pthread_mutex_unlock.

如果线程不希望被阻塞,他可以使用 pthread_mutex_trylock 尝试对互斥量进行加锁。如果调用 pthread_mutex_trylock 时互斥量处于未锁住状态,那么 pthread_mutex_trylock 将锁住互斥量,否则就会失败,不能锁住互斥量,而返回 EBUSY

 

6 互斥锁创建

有两种方法创建互斥锁,静态方式和动态方式。

A POSIX 定义了一个宏 PTHREAD_MUTEX_INITIALIZER 来静态初始化互斥锁,方法如下:

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

B: 动态方式是采用 pthread_mutex_init() 函数来初始化互斥锁, API 定义如下:

int pthread_mutex_init(pthread_mutex_t *mutex, constpthread_mutexattr_t *mutexattr);

其中 mutexattr 用于指定互斥锁属性,如果为 NULL 则使用缺省属性。

C: pthread_mutex_destroy () 用于注销一个互斥锁, API 定义如下:

    intpthread_mutex_destroy(pthread_mutex_t *mutex);

D:pthread_mutex_lock() 加锁

E:pthread_mutex_unlock() 解锁

F:pthread_mutex_trylock() 测试加锁

G: 释放内存前需要调用 pthread_mutex_destory.

案例说明互斥量加锁的必要性:

#include<stdio.h>

#include<pthread.h>

#include<stdlib.h>

#include<unistd.h>

 

void *thread_function(void *arg);

/* run_now 代表共享资源 */

int run_now = 1;

 

int main(void)

{

    int print_count1 = 0;/* 用于循环控制 */

    pthread_t a_thread;

 

    /* 创建一个进程 */

    if(pthread_create(&a_thread,NULL,thread_function,NULL)){

        perror("Thread creation failed!");

        exit(1);

    }

 

    while(print_count1++ < 5){

        /* 主线程:如果 run_now 1 就把它修改为 2*/

        if(run_now == 1) {

            printf("main thread is run\n");

            run_now = 2;

        } else {

            printf("main thread is sleep\n");

            sleep(1);

        }

    }

         // 等待子线程结束

    pthread_join(a_thread,NULL);

    exit(0);

}

 

void *thread_function(void *arg) {

   int print_count2 = 0;

   while(print_count2++ < 5){

       if(run_now == 2) /* 子线程:如果 run_now 1 就把它修改为 1*/

       {

           printf("function thread is run\n");

           run_now = 1;

       }

       else

       {

           printf("function thread is sleep\n");

           sleep(1);

       }

   }

   pthread_exit(NULL);

}

运行结果:

现象: main 线程和 function 线程是交替运行的。它们都可以对 run_now 进行操作。

加锁后的代码

#include <stdio.h>

#include <pthread.h>

#include <stdio.h>

#include <stdlib.h>

 

void *thread_function(void *arg);

int run_now=1;   /* run_now 代表共享资源 */

pthread_mutex_t work_mutex;   /* 定义互斥量 */

 

int main(void) {

    int res;

    int print_count1=0;

    pthread_t a_thread;

 

    if(pthread_mutex_init(&work_mutex,NULL)!=0)   /* 初始化互斥量 */

    {

        perror("Mutex init faied");

        exit(1);

    }

 

    if(pthread_create(&a_thread,NULL,thread_function,NULL)!=0)   /* 创建新线程 */

    {

        perror("Thread createion failed");

        exit(1);

    }

 

    if(pthread_mutex_lock(&work_mutex)!=0)   /* 对互斥量加锁 */

    {

        perror("Lock failed");

        exit(1);

    } else {

        printf("main lock\n");

    }

 

    while(print_count1++<5) {

        if(run_now == 1)   /* 主线程:如果 run_now 1 就把它修改为 2*/

        {

            printf("main thread is run\n");

            run_now=2;

        } else {

            printf("main thread is sleep\n");

            sleep(1);

        }

    }

 

    if(pthread_mutex_unlock(&work_mutex)!=0) /* 对互斥量解锁 */

    {

        perror("unlock failed");

        exit(1);

    } else {

        printf("main unlock\n");

    }

 

    pthread_mutex_destroy(&work_mutex); /* 收回互斥量资源 */

    pthread_join(a_thread,NULL); /* 等待子线程结束 */

    exit(0);

}

 

void *thread_function(void *arg) {

    int print_count2=0;

    sleep(1);

 

    if(pthread_mutex_lock(&work_mutex)!=0) {

        perror("Lock failed");

        exit(1);

    } else {

        printf("function lock\n");

    }

   

    while(print_count2++<5) {

        if(run_now==2)   /* 分进程:如果 run_now 1 就把它修改为 1*/

        {

            printf("function thread is run\n");

            run_now=1;

        } else {

            printf("function thread is sleep\n");

            sleep(1);

        }

    }

 

    if(pthread_mutex_unlock(&work_mutex)!=0)   /* 对互斥量解锁 */

    {

        perror("unlock failed");

        exit(1);

    } else {

        printf("function unlock\n");

    }

    pthread_exit(NULL);

}

运行结果如下:

总结:从运行结果可以看到,当主进程把互斥量锁住后,子进程就不能对共享资源进行操作了,只能是同步的操作了。

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

#define NLOOP 5000

 

int counter;

pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;

 

void *doit(void *);

 

int main(int argc,char **argv){

    pthread_t tidA,tidB;

 

    pthread_create(&tidA,NULL,doit,NULL);

    pthread_create(&tidB,NULL,doit,NULL);

 

    /*wait for both thread to terminate*/

    pthread_join(tidA,NULL);

    pthread_join(tidB,NULL);

 

    return 0;

}

 

void *doit(void *vptr){

    int i,val;

    for(i = 0;i < NLOOP;i++) {

        pthread_mutex_lock(&counter_mutex);

        val = counter;

        printf("%x:%d\n",(unsigned int) pthread_self(),val + 1);

        counter = val + 1;

 

        pthread_mutex_unlock(&counter_mutex);

    }

 

    return NULL;

}

运行结果:

  1. 死锁

    A 同一个线程在拥有 A 锁的情况下再次请求获得 A

    B 线程一拥有 A 锁,请求获得 B 锁;线程二拥有 B 锁,请求获得 A 锁,出现死锁,最终导致的结果是互相等待。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章