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

什么是线程同步?

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

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;
}
相关推荐
Lary_Rock1 小时前
RK3576 LINUX RKNN SDK 测试
linux·运维·服务器
云飞云共享云桌面3 小时前
8位机械工程师如何共享一台图形工作站算力?
linux·服务器·网络
Peter_chq4 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
wheeldown4 小时前
【数据结构】选择排序
数据结构·算法·排序算法
一坨阿亮4 小时前
Linux 使用中的问题
linux·运维
dsywws5 小时前
Linux学习笔记之vim入门
linux·笔记·学习
幺零九零零6 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
小林熬夜学编程8 小时前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法
躺不平的理查德8 小时前
数据结构-链表【chapter1】【c语言版】
c语言·开发语言·数据结构·链表·visual studio
阿洵Rain8 小时前
【C++】哈希
数据结构·c++·算法·list·哈希算法