用互斥锁、信号量、条件变量实现线程同步

什么是线程同步?

线程同步指的是当一个线程在对某个临界资源进行操作时,其他线程都不可以对这个资源进行操作,直到该线程完成操作。

pthread_create()

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);//用于创建新的线程

//*thread,指向线程标识符的指针,用于存储新线程的标识符

//attr,通常位NULL

//start_routine,指向线程主函数的指针,新线程将从这个函数开始执行

//arg,传递给 start_routine 的参数

//成功返回0,错误返回错误码

pthread_join()

int pthread_join(pthread_t thread, void **retval);//用于等待一个线程结束并回收其资源

//thread,要等待的线程的标识符

//retval,存储被等待线程的返回值的地址。如果不关心返回值,可以传递 NULL

//成功返回0,错误返回错误码

互斥锁

pthread_mutex_init()

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);//初始化互斥量

//mutex,指向要初始化的互斥锁的指针

//attr,指向线程属性对象的指针。如果传递 NULL,则使用默认的属性

//成功返回0,错误返回错误码

pthread_mutex_lock()

int pthread_mutex_lock(pthread_mutex_t *mutex);//用于对指定的互斥量进行加锁

//mutex,指向互斥量的指针

//成功返回0,错误返回错误码

pthread_mutex_unlock()

int pthread_mutex_unlock(pthread_mutex_t *mutex); //用于解锁之前由 pthread_mutex_lock 函数锁定的互斥量

//mutex,指向互斥量的指针

//成功返回0,错误返回错误码

pthread_mutex_destroy()

int pthread_mutex_destroy(pthread_mutex_t *mutex); //用于销毁互斥锁

//mutex,指向待销毁的互斥锁的指针

//成功返回0,错误返回错误码

实践

主线程和函数线程模拟访问打印机,主线程输出第一个字符'a'表示开始使用打印机,输出第二个字符'a'表示结束使用,函数线程操作与主线程相同。

cpp 复制代码
#include<iostream>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
//#include <semaphore.h>

using namespace std;

pthread_mutex_t mutex;

void *thread_fun(void *arg)
{
    int i = 0;
    for (; i < 5; i++)
    {
        pthread_mutex_lock(&mutex);
        write(1, "B", 1);
        // cout << "B";fflush(stdout);
        sleep(rand() % 3); // 随机睡眠一段时间,用于模拟线程在做其他事情
         write(1, "B", 1);
        //cout << "B"; fflush(stdout);
        pthread_mutex_unlock(&mutex);
        sleep(rand() % 3);
    }

    pthread_exit(NULL);
}

int main()
{
    pthread_t id;

    pthread_mutex_init(&mutex, NULL);
    pthread_create(&id, NULL, thread_fun, NULL);

    int i = 0;
    for (; i < 5; i++)
    {
        pthread_mutex_lock(&mutex);
        write(1, "A", 1);
        //cout << "A"; fflush(stdout);
        sleep(rand() % 3);
        write(1, "A", 1);
        //cout << "A"; fflush(stdout);
        pthread_mutex_unlock(&mutex);
        sleep(rand() % 3);
    }

    pthread_join(id, NULL);

    pthread_mutex_destroy(&mutex);
    cout << endl;

    exit(0);
}

输出结果:AABBAABBAABBAABBAABB

信号量

sem_init()

int sem_init(sem_t *sem, int pshared, unsigned int value);//初始化信号量

//sem,指向要初始化的信号量的指针

//value,信号量的初始值

sem_wait()

int sem_wait(sem_t *sem);//等待信号量

//sem,指向要初始化的信号量的指针

sem_post()

int sem_post(sem_t *sem);//释放信号量

//sem,指向要初始化的信号量的指针

sem_destroy()

int sem_destroy(sem_t *sem);//销毁信号量

//sem,指向要初始化的信号量的指针

实践

实现一个基于线程和信号量的简单的生产者-消费者模型,主线程用于从用户输入中获取数据,子线程读取数据并将其写入文件。

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <fcntl.h>

using namespace std;

char buff[128] = {0};

sem_t sem1;
sem_t sem2;

void *PthreadFun(void *arg)
{
    int fd = open("a.txt", O_RDWR | O_CREAT, 0664);
    if (fd == -1)
    {
        cout << "open failed" << endl;
    }

    // 函数线程完成将用户输入的数据存储到文件中
    while (1)
    {
        sem_wait(&sem2);

        if (strncmp(buff, "end", 3) == 0)
        {
            break;
        }

        write(fd, buff, strlen(buff));
        memset(buff, 0, 128);

        sem_post(&sem1);
    }

    sem_destroy(&sem1);
    sem_destroy(&sem2);

    return NULL;
}

int main()
{
    sem_init(&sem1, 0, 1);
    sem_init(&sem2, 0, 0);

    pthread_t id;
    int res = pthread_create(&id, NULL, PthreadFun, NULL);

    // 主线程完成获取用户数据的数据,并存储在全局数组 buff 中
    while (1)
    {
        sem_wait(&sem1);

        cout << "please input data: " << endl;

        //fgets(buff, 128, stdin);
        cin >> buff;
        //buff[strlen(buff) - 1] = 0;
        buff[strlen(buff)] = 0;
        sem_post(&sem2);

        if (strncmp(buff, "end", 3) == 0)
        {
            break;
        }
    }

    return 0;
}

条件变量

条件变量提供了一种线程间的通知机制:当某个共享数据达到某个值的时候,唤醒等待

这个共享数据的线程。

pthread_cond_init()

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);//初始化条件变量

//cond,指向要初始化的条件变量的指针

//attr,通常为NULL

pthread_cond_wait()

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);//在满足某个条件之前让线程进入等待状态

//cond,指向条件变量的指针

//mutex,指向互斥锁的指针

pthread_cond_signal()

int pthread_cond_signal(pthread_cond_t *cond);//向等待在条件变量上的单个线程发送信号

//cond,指向条件变量的指针

pthread_cond_broadcast()

int pthread_cond_broadcast(pthread_cond_t *cond); //向等待在条件变量上的所有线程发送信号

//cond,指向条件变量的指针

pthread_cond_destroy()

int pthread_cond_destroy(pthread_cond_t *cond);//销毁条件变量

//cond,指向条件变量的指针

实践

使用条件变量和互斥锁使两个线程交替输出信息。

cpp 复制代码
#include<iostream>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>

using namespace std;

pthread_mutex_t mutex;
pthread_cond_t cond;

void *fun1(void *arg)
{
    char *s = (char *)arg;
    while (1)
    {
        // 阻塞,被唤醒
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond, &mutex);
        pthread_mutex_unlock(&mutex);

        cout << "fun1 read:" << s << endl;

        if (strncmp(s, "end", 3) == 0)
        {
            break;
        }
    }

    return NULL;
}

void *fun2(void *arg)
{
    char *s = (char *)arg;
    while (1)
    {
        // 阻塞,被唤醒
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond, &mutex);
        pthread_mutex_unlock(&mutex);

        cout << "fun2 read:" << s << endl;

        if (strncmp(s, "end", 3) == 0)
        {
            break;
        }
    }

    return NULL;
}

int main()
{
    pthread_t id[2];
    char buff[128] = {0};

    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);
    pthread_create(&id[0], NULL, fun1, (void *)buff);
    pthread_create(&id[1], NULL, fun2, (void *)buff);

    while (1)
    {
        cin >> buff;
        if (strncmp(buff, "end", 3) == 0)
        {
            pthread_mutex_lock(&mutex);
            pthread_cond_broadcast(&cond);
            pthread_mutex_unlock(&mutex);

            break;
        }
        else
        {
            pthread_mutex_lock(&mutex);
            pthread_cond_signal(&cond);
            pthread_mutex_unlock(&mutex);
        }
    }

    pthread_join(id[0], NULL);
    pthread_join(id[1], NULL);

    pthread_cond_destroy(&cond);

    return 0;
}
相关推荐
雨中rain1 分钟前
Linux -- 从抢票逻辑理解线程互斥
linux·运维·c++
就爱学编程3 分钟前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
Bessssss21 分钟前
centos日志管理,xiao整理
linux·运维·centos
s_yellowfish21 分钟前
Linux服务器pm2 运行chatgpt-on-wechat,搭建微信群ai机器人
linux·服务器·chatgpt
豆是浪个22 分钟前
Linux(Centos 7.6)yum源配置
linux·运维·centos
vvw&24 分钟前
如何在 Ubuntu 22.04 上安装 Ansible 教程
linux·运维·服务器·ubuntu·开源·ansible·devops
我一定会有钱25 分钟前
【linux】NFS实验
linux·服务器
Ven%29 分钟前
如何在防火墙上指定ip访问服务器上任何端口呢
linux·服务器·网络·深度学习·tcp/ip
是阿建吖!36 分钟前
【Linux】基础IO(磁盘文件)
linux·服务器·数据库
张暮笛43 分钟前
蓝牙协议——音量控制
linux