Linux下多任务间通信和同步-互斥锁

来源:互联网 发布:最美天气网数据来源 编辑:程序博客网 时间:2024/05/18 01:10

Linux下多任务间通信和同步-互斥锁

嵌入式开发交流群280352802,289195589欢迎加入!

概述

互斥锁(Mutex)是一种简单的通过加锁的方法来控制对共享资源的存取,一般用于解决线程间资源访问的唯一性问题.
互斥锁其实很简单,它只有两种状态:上锁和解锁.在同一时刻只能有一个线程掌握某个互斥的锁,拥有上锁状态的线程能够对共享资源进行操作.若其他线程希望对一个已经上了锁的互斥锁上锁,则该线程就会挂起,直到上锁的线程释放掉互斥锁为止.操作互斥锁的基本函数与信号量用到的函数相似,主要包括以下这些.

  • pthread_mutex_init:互斥锁初始化;
  • pthread_mute_lock:互斥锁上锁(阻塞版);
  • pthread_mutex_trylock:互斥锁上锁(非阻塞版);
  • pthread_mutex_unlock:互斥锁解锁;
  • pthread_mutex_destory:消除互斥锁.
线程互斥锁的数据类型是pthread_mutex_t,在使用前,要对其进行初始化,有下列两种方法:
  1. 静态初始化:可以把PTHREAD_MUTEX_INITIALIZER常量赋值给静态分配的互斥锁变量.
  2. 动态初始化:在申请内存(malloc)之后,通过pthread_mute_init进行初始化.注意在释放内存前需要调用pthread_mutex_destory.

系统调用pthread_mutex_init()

该系统该调用初始化互斥锁变量mutex.其原型为:
#include <pthread.h>int pthread_mutex_init(pthread_mutex_t*mutex, const pthread_mutexattr_t *mutexattr);

参数mutex:是pthread_mutex_t数据类型的指针;
参数mutexattr:是互斥锁的属性,通常只需设置为NULL,即以默认的属性初始化互斥锁.

系统调用pthread_mutex_lock()

     该系统调用对互斥锁枷锁,其原型为:
#include <pthread.h> int pthread_mutex_lock(pthread_mutex_t*mutex);
     对于一个已上锁的互斥锁,若调用pthread_mutex_lock()函数再次加锁,将使调用线程阻塞,直到互斥锁被解锁.调用成功发那会0,失败返回-1.参数mutex是pthread_mutex_t数据类型的指针。

系统调用pthread_mutex_trylock()

     该系统调用对互斥锁mutex加锁.其原型为:
#include <pthread.h>
Int pthread_mutex_trylock(pthread_mutex_t*mutex); 
对于一个已上锁的互斥锁,若调用pthread_mutex_trylock()函数再次加锁,将返回错误EBUSY(已加锁错误),因而不会发生阻塞.对于未上锁的情况,该函数将对互斥锁加锁.调用成功返回0,失败返回-1.

系统调用pthread_mutex_unlock()

该系统调用解除mutex所指的互斥锁,其原型为:
#include <pthread.h>int pthread_mutex_unlock(pthread_mutex_t*mutex);

系统调用pthread_mutex_destory()

该系统清除mutex所指的互斥锁,其原型为:
#include <pthreadl.h>int pthread_mutex_destory(pthread_mutex_t*mutex); 
对于动态分配的互斥锁变量,在释放内存前需要调用该函数清楚pthread_mutex_t结构.

互斥锁的应用实例

/**************************************************************************************//*简介:互斥锁同步线程演示程序 *//*************************************************************************************/#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <pthread.h>#include <semaphore.h>#include <string.h>void *thread_function(void *arg);pthread_mutex_t work_mutex; #define WORK_SIZE 1024char work_area[WORK_SIZE];/*工作区*/int time_to_exit = 0;/*退出程序标志*/int main() {    int res;    pthread_t a_thread;    void *thread_result;    /*对互斥锁进行初始化*/    res = pthread_mutex_init(&work_mutex, NULL);    if (res != 0)     {        perror("Mutex initialization failed");        return 1;    }    res = pthread_create(&a_thread, NULL, thread_function, NULL);    if (res != 0)     {        perror("Thread creation failed");        return 1;    }    /*给工作区加上锁,把文本读到它里面,    然后给它解锁使它允许被其他线程访问*/    pthread_mutex_lock(&work_mutex);    printf("Input some text. Enter 'end' to finish\n");    while(!time_to_exit)     {        fgets(work_area, WORK_SIZE, stdin);        pthread_mutex_unlock(&work_mutex);        while(1) {            pthread_mutex_lock(&work_mutex);            if (work_area[0] != '\0')     {                pthread_mutex_unlock(&work_mutex);                sleep(1);            }            else     {                break;            }        }    }    pthread_mutex_unlock(&work_mutex);    printf("\nWaiting for thread to finish...\n");    res = pthread_join(a_thread, &thread_result);    if (res != 0)     {        perror("Thread join failed");        return 1;    }    printf("Thread joined\n");    pthread_mutex_destroy(&work_mutex);    return 0;}
在主线程中,首先对工作区加上锁,把文本读到它里面,然后给它解锁使它允许被其他子线程访问并对其中的字符个数进行统计.主线程周期性地对互斥量进行加锁,检查是都已经统计完了,如果还需要等待就释放互斥量.

void *thread_function(void *arg) {    sleep(1);    /*新线程首先试图对互斥量进行加锁*/    pthread_mutex_lock(&work_mutex);    while(strncmp("end", work_area, 3) != 0)     {        printf("You input %d characters\n", strlen(work_area) -1);        /*把第一个字符设置为空字符已经完成了字符统计工作*/        work_area[0] = '\0';        /*对互斥量进行解锁并等待主线程的运行*/        pthread_mutex_unlock(&work_mutex);        sleep(1);        /*周期性地尝试给互斥量加锁,如果加锁成功,        就检查主线程是否有新的字符需要统计。        如果还没有,就解开互斥量继续等待*/        pthread_mutex_lock(&work_mutex);        while (work_area[0] == '\0' ) {            pthread_mutex_unlock(&work_mutex);            sleep(1);            pthread_mutex_lock(&work_mutex);        }    }    /*设置退出程序的标志*/    time_to_exit = 1;    work_area[0] = '\0';    pthread_mutex_unlock(&work_mutex);    pthread_exit(0);}
新线程启动时后弦尝试对互斥量进行加锁.如果它已经被锁上了,调用将被阻塞到它被释放为止.一旦有了访问权,线程将先检查是都有退出程序的请求.如果有则设置好time_to_exit变量,再把工作区里的第一个字符设置为"\0",然后退出线程.

如果不退出程序,就对字符个数进行统计,然后把工作区里的第一个字符设置为NULL.子线程用把第一个字符设置为空字符的方式告诉主线程可以继续输入,表明子线程已经完成了字符统计的工作.接下来,子线程对互斥量进行解锁并等待主线程的运行.子线程周期性地尝试给互斥量加锁,如果加锁成功,就检查主线程是否有送来另外一些字符准备统计.如果没有,就释放互斥量继续等待;如果有,就统计并在此进入刚才的循环.下图是程序的运行结果:


原创粉丝点击