ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c++项目中 锁的使用

2021-10-10 11:32:13  阅读:199  来源: 互联网

标签:线程 函数 项目 pthread c++ mutex 使用 cond 变量


有一定的操作系统基础,互斥,信号量都有一定了解。 了解一下在项目中用到的锁。

1.首先是是初始化和去初始化,这两个函数都是库文件,可以直接调用,他们包含在头文件<pthread.h>中

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);

初始化和去初始化我们一般写在构造函数和析构函数里面,如果初始化返回的不是0,说明初始化失败,抛出异常
在这里插入图片描述
除了使用 pthread_mutex_init 函数对 mutex 进行初始化,还可以使用特定的宏在声明 mutex 的时候直接赋值进行静态初始化。

ps:重复初始化一个已经初始化过的锁会导致未知行为。
如果尝试销毁一个锁定状态的mutex会导致未知行为。

2.加锁与解锁也是库函数,直接调用

// 普通加锁,重复加锁会阻塞进程
int pthread_mutex_lock (pthread_mutex_t *__mutex);
// 重复加锁不阻塞进程
int pthread_mutex_trylock (pthread_mutex_t *__mutex);
// 带有超时功能加锁
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout);
// 解锁
int pthread_mutex_unlock (pthread_mutex_t *__mutex);

根据函数原型,函数的返回值都是整数,如果返回结果为0表示加锁成功,返回相应的bool值。
在这里插入图片描述
3.定义一个线程
pthread_mutex_t m_mutex;

4.创建线程

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg) 

thread 指向线程标识符指针。
attr 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。
start_routine 线程运行函数起始地址,一旦线程被创建就会执行。
arg 运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。

5.终止线程
#include <pthread.h>
pthread_exit (status)

pthread_exit() 函数是在线程完成工作后无需继续存在时被调用。

如果 main() 是在它所创建的线程之前结束,并通过 pthread_exit() 退出,那么其他线程将继续执行。否则,它们将在 main() 结束时自动被终止。

6.关于上述应用实例

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

int gValue=0;
pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;

void *add(void*){
    pthread_mutex_lock(&gMutex);    // 加锁
    for (int i = 0; i < 10; ++i) {
        printf("[1]%d ", ++gValue);
    }
    pthread_mutex_unlock(&gMutex);  // 解锁
}

void *sub(void*){
    pthread_mutex_lock(&gMutex);  // 加锁
    for (int i = 0; i < 10; ++i) {
        printf("[2]%d ", --gValue);
    }
    pthread_mutex_unlock(&gMutex);  // 解锁
}


int main() {
    pthread_t p1, p2;

    pthread_create(&p1, NULL, add, NULL);
    pthread_create(&p2, NULL, sub, NULL);

    pthread_join(p1, NULL);
    pthread_join(p2, NULL);

    return 0;
}

关于条件变量
1.定义
pthread_cond_t m_cond;

2.初始化和去初始化,同样写在构造函数和析构函数中
返回值:函数成功返回0;任何其他返回值都表示错误

int pthread_cond_init(pthread_cond_t *cv,
const pthread_condattr_t *cattr);

参数是线程和属性:初始化一个条件变量。当参数cattr为空指针时,函数创建的是一个缺省的条件变量。否则条件变量的属性将由cattr中的属性值来决定。这个函数返回时,条件变量被存放在参数cv指向的内存中。

cond()
    {
        if (pthread_cond_init(&m_cond, NULL) != 0)
        {
            //pthread_mutex_destroy(&m_mutex);
            throw std::exception();
        }
    }
    ~cond()
    {
        pthread_cond_destroy(&m_cond);
    }

释放条件变量。

注意:条件变量占用的空间并未被释放。

2.阻塞在条件变量上pthread_cond_wait

函数将解锁m_mutex参数指向的互斥锁,并使当前线程阻塞在m_cond参数指向的条件变量上。

  pthread_cond_wait(&m_cond, m_mutex);

pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,必须重新检查条件的值。

pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,即使是函数出错返回。

一般一个条件表达式都是在一个互斥锁的保护下被检查。当条件表达式未被满足时,线程将仍然阻塞在这个条件变量上。当另一个线程改变了条件的值并向条件变量发出信号时,等待在这个条件变量上的一个线程或所有线程被唤醒,接着都试图再次占有相应的互斥锁。

阻塞在条件变量上的线程被唤醒以后,直到pthread_cond_wait()函数返回之前条件的值都有可能发生变化。所以函数返回以后,在锁定相应的互斥锁之前,必须重新测试条件值。最好的测试方法是循环调用pthread_cond_wait函数,并把满足条件的表达式置为循环的终止条件。如:

pthread_mutex_lock();
while (condition_is_false)
 pthread_cond_wait();
pthread_mutex_unlock();

阻塞在同一个条件变量上的不同线程被释放的次序是不一定的。
pthread_cond_wait()函数是退出点,如果在调用这个函数时,已有一个挂起的退出请求,且线程允许退出,这个线程将被终止并开始执行善后处理函数,而这时和条件变量相关的互斥锁仍将处在锁定状态。

3.阻塞直到指定时间pthread_cond_timedwait
#include <pthread.h>
#include <time.h>

 bool timewait(pthread_mutex_t *m_mutex, struct timespec t)
    {
        int ret = 0;
        //pthread_mutex_lock(&m_mutex);
        ret = pthread_cond_timedwait(&m_cond, m_mutex, &t);
        //pthread_mutex_unlock(&m_mutex);
        return ret == 0;
    }

函数到了一定的时间,即使条件未发生也会解除阻塞。这个时间由参数t指定

pthread_cond_timedwait函数也是退出点。

4.解除在条件变量上的阻塞pthread_cond_signal

 bool signal()
    {
        return pthread_cond_signal(&m_cond) == 0;
    }

函数被用来释放被阻塞在指定条件变量上的一个线程。

必须在互斥锁的保护下使用相应的条件变量。否则对条件变量的解锁有可能发生在锁定条件变量之前,从而造成死锁。

唤醒阻塞在条件变量上的所有线程的顺序由调度策略决定,如果线程的调度策略是SCHED_OTHER类型的,系统将根据线程的优先级唤醒线程。

5.释放阻塞的所有线程pthread_cond_broadcast

bool broadcast()
    {
        return pthread_cond_broadcast(&m_cond) == 0;
    }

函数唤醒所有被pthread_cond_wait函数阻塞在某个条件变量上的线程。


标签:线程,函数,项目,pthread,c++,mutex,使用,cond,变量
来源: https://blog.csdn.net/zhazhali_fenqi/article/details/120683086

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有