设为首页 加入收藏

TOP

线程同步(一)
2019-09-15 00:33:37 】 浏览:85
Tags:线程 同步

1. 线程同步概述

线程同步定义

线程同步,指的是控制多线程间的相对执行顺序,从而在线程间正确、有序地共享数据,以下为线程同步常见使用场合。

  • 多线程执行的任务在顺序上存在依赖关系
  • 线程间共享数据只能同时被一个线程使用

线程同步方法

在实际项目中,经常使用的线程同步方法主要分为三种:

  • 互斥锁
  • 条件变量
  • Posix信号量(包括有名信号量和无名信号量)

本节内容只介绍互斥锁和条件变量,Posix信号量后续在Posix IPC专题中介绍。

2. 互斥锁

互斥锁概念

互斥锁用于确保同一时间只有一个线程访问共享数据,使用方法为:

  • 加锁
  • 访问共享数据
  • 解锁

对互斥锁加锁后,任何其他试图再次对其加锁的线程都会被阻塞,直到当前线程释放该互斥锁,解锁时所有阻塞线程都会变成可运行状态,但究竟哪个先运行,这一点是不确定的。

互斥锁基本API

初始化与销毁

互斥锁是用pthread_mutex_t数据类型表示的,在使用互斥锁之前,需要先进行初始化,初始化方法有两种:

  • 设置为常量PTHREAD_MUTEX_INITIALIZER,只适用于静态分配的互斥锁
  • 调用pthread_mutex_init函数,静态分配和动态分配的互斥锁都可以

互斥锁使用完以后,可以调用pthread_mutex_destroy进行销毁,尤其是对于动态分配的互斥锁,在释放内存前,调用pthread_mutex_destroy是必须的。

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//两个函数的返回值:成功返回0,失败返回错误编号
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);

其中,pthread_mutex_init的第二个参数attr用于设置互斥锁的属性,如果要使用默认属性,只需把attr设为NULL。

上锁与解锁

//两个函数的返回值:成功返回0,失败返回错误编号
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

对互斥锁上锁,需要调用pthread_mutex_lock,如果互斥锁已经上锁,调用线程将阻塞到该互斥锁被释放。
对互斥锁解锁,需要调用pthread_mutex_unlock

两个特殊的上锁函数

尝试上锁

//成功返回0,失败返回错误编号
int pthread_mutex_trylock(pthread_mutex_t *mutex);

如果不希望调用线程阻塞,可以使用pthread_mutex_trylock尝试上锁:

  • 若mutex未上锁,pthread_mutex_trylock将加锁成功,返回0
  • 若mutex已上锁,pthread_mutex_trylock会加锁失败,返回EBUSY

限时上锁

//成功返回0,失败返回错误编号
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *time);

pthread_mutex_timedlock是一个可以设置阻塞时间的上锁函数:

  • 当mutex已上锁时,调用线程会阻塞设定的时间
  • 当达到设定时间时,pthread_mutex_timedlock将加锁失败并解除阻塞,返回ETIMEDOUT

关于第二个参数time,有两点需要注意:

  • time表示等待的绝对时间,需要将其设为当前时间 + 等待时间
  • time是由struct timespec指定的,它由秒和纳秒来描述时间

示例代码

/*
 * 测试使用上述4个加锁函数
*/

#include <pthread.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>

pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
pthread_mutex_t mutex3;

void *thread1_start(void *arg)
{
    pthread_mutex_lock(&mutex1);
    printf("thread1 has locked mutex1\n");
    sleep(2); //保证thread2执行时mutex1还未解锁
    pthread_mutex_unlock(&mutex1);
}

void *thread2_start(void *arg)
{
    if (pthread_mutex_trylock(&mutex2) == 0)
        printf("thread2 trylock mutex2 sucess\n");

    if (pthread_mutex_trylock(&mutex1) == EBUSY)
        printf("thread2 trylock mutex1 failed\n");
          
    pthread_mutex_unlock(&mutex2);
}

void *thread3_start(void *arg)
{
    struct timespec time;
    struct tm *tmp_time;
    char s[64];
    int err;
    
    pthread_mutex_lock(&mutex3);
    printf("thread3 has locked mutex3\n");
    
    /*获取当前时间,并转化为本地时间打印*/
    clock_gettime(CLOCK_REALTIME, &time);
    tmp_time = localtime(&time.tv_sec);
    strftime(s, sizeof(s), "%r", tmp_time);
    printf("current time is %s\n", s);
    
    /*设置time = 当前时间 + 等待时间10S*/
    time.tv_sec = time.tv_sec + 10;
    
    /*mutex3已上锁,这里会阻塞*/
    if (pthread_mutex_timedlock(&mutex3, &time) == ETIMEDOUT)
        printf("pthread_mutex_timedlock mutex3 timeout\n");
    
    /*再次获取当前时间,并转化为本地时间打印*/
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Ubuntu14.04中stopping log initi.. 下一篇Dockfile 生成docker镜像文件大小..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目