两个线程同步执行:解决乱箭穿心(STL/Windows/Linux)

C++自学精简教程 目录(必读)

C++并发编程入门 目录

多线程同步

线程之间同步是指线程等待其他线程执行完某个动作之后再执行(本文情况)。

线程同步还可以是像十字路口的红绿灯一样,只允许一个方向的车同行,其他方向的车等待。

本文将使用信号量来实现线程同步。

一个线程通知另一个线程,另一个线程等待被通知信号。

一个发送线程先往控制台上打印1,这时候接收线程并不往控制台打印2,而是等待发送线程发给自己的信号,等到信号之后再打印2.

每次发送线程打印完自己的数据之后,睡眠1毫秒,给接收线程时间来完成自己的工作。

睡眠1毫秒合理吗?

这里睡眠1毫秒是合理的。

多个线程在协调工作的时候,每个线程都会需要时间来才能解决问题。

所以作为协调源头的线程1,应该给其他线程时间来处理问题,这是合理的。

例如,在音视频开发中,采集是源头,比如120HZ的视频,时间间隔是8.333ms,所有后续的编码线程,推流线程,等等,都需要在这有限的8.333毫秒之内完成自己的工作。

STL 写法

cpp 复制代码
// condition_variable::notify_one
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <chrono>             //milliseconds
using namespace std;
using namespace chrono;

std::mutex mutex1;
std::condition_variable event;

void thread_sender_fun(void)
{
    while (true)
    {
        cout << "1";
        event.notify_one();
        this_thread::sleep_for(milliseconds(1));
    }
}

void thread_receiver_fun()
{
    while (true)
    {
        std::unique_lock<std::mutex> lock(mutex1);
        event.wait(lock);
        cout << "2";
    }
}

int main()
{
    std::thread thread_sender(thread_sender_fun);
    std::thread thread_receiver(thread_receiver_fun);

    // join them back:
    thread_sender.join();
    thread_receiver.join();

    return 0;
}

Windows 写法

cpp 复制代码
#include <windows.h>
#include <iostream>
using namespace std;

HANDLE event;//事件对象

DWORD WINAPI sender_event_thread_fun(LPVOID lpParam)
{
    while (true)
    {
        cout << "1";//干活
        SetEvent(event);//发出写完成信号,通知另一个线程该打印2了
        Sleep(1);
    }
    return 0;
}

DWORD WINAPI receive_event_thread_fun(LPVOID lpParam)
{
    UNREFERENCED_PARAMETER(lpParam);
    while (true)
    {
        DWORD dwWaitResult = WaitForSingleObject(event, INFINITE);// 等待信号,无限等待
        cout << "2";//干活
    }
    return 0;
}

int main(void)
{
    event = CreateEvent(NULL,
        //是否需要人工ResetEvent重置为无信号状态:
        //是:当该事件为有信号状态时,所有等待该信号的线程都变为可调度线程。
        //      并且,需要手动调用ResetEvent为无信号状态;
        //否:当该事件为有信号状态时,只有一个线程变为可调度线程。
        //      并且,系统自动调用ResetEvent将该对象设置为无信号状态。(一次性的信号)
        FALSE,
        FALSE,//初始状态:无信号状态
        TEXT("WriteFinishedEvent")// 事件对象名称
    );

    //创建线程
    HANDLE thread_sender  = CreateThread(NULL, 0, sender_event_thread_fun, NULL, 0, NULL);
    HANDLE thread_receive = CreateThread(NULL, 0, receive_event_thread_fun, NULL, 0, NULL);
    
    HANDLE handleArr[] = { thread_sender , thread_receive };
    
    //等待线程执行结束
    WaitForMultipleObjects(2, handleArr, TRUE, INFINITE);
    
    //释放资源
    CloseHandle(thread_sender);
    CloseHandle(thread_receive);
    CloseHandle(event);

    return 0;
}

不再乱箭穿心,总是先打印1,后打印2

Linux 写法

cpp 复制代码
#include <pthread.h>
#include <semaphore.h>
#include <iostream>
#include <unistd.h>//usleep
using namespace std;

sem_t event;

void* thread_sender_fun(void* arg)
{
    while (true)
    {
        cout << "1";
        sem_post(&event);
        usleep(1000);//休眠一毫秒
    }
    
    return 0;
}

void* thread_receive_fun(void* arg)
{
    while (true)
    {
        sem_wait(&event);
        cout << "2";
    }
    
    return 0;
}

int main(int argc, char *argv[])
{
    pthread_t thread_sender;
    pthread_t thread_receiver;

    sem_init(&event, 0, 0);

    pthread_create(&thread_sender, NULL, thread_sender_fun, NULL);
    pthread_create(&thread_receiver, NULL, thread_receive_fun, NULL);

    pthread_join(thread_sender, NULL);
    pthread_join(thread_receiver, NULL);

    return 0;
}

不再乱箭穿心,总是先打印1,后打印2

相关推荐
KBDYD1010几秒前
C语言--结构体变量和数组的定义、初始化、赋值
c语言·开发语言·数据结构·算法
计算机学姐3 分钟前
基于python+django+vue的影视推荐系统
开发语言·vue.js·后端·python·mysql·django·intellij-idea
狐心kitsune4 分钟前
erlang学习:Linux常用命令1
linux·学习·erlang
Crossoads20 分钟前
【数据结构】排序算法---桶排序
c语言·开发语言·数据结构·算法·排序算法
扎克begod25 分钟前
JAVA并发编程系列(9)CyclicBarrier循环屏障原理分析
java·开发语言·python
偷偷小野猪28 分钟前
想要自动删除浏览器历史记录吗?这样设置就对了
windows·edge浏览器
code bean33 分钟前
【C#基础】函数传参大总结
服务器·开发语言·c#
Hqst_Kevin40 分钟前
Hqst 品牌 H81801D 千兆 DIP 网络变压器在光猫收发器机顶盒中的应用
运维·服务器·网络·5g·网络安全·信息与通信·信号处理
阳光阿盖尔42 分钟前
EasyExcel的基本使用——Java导入Excel数据
java·开发语言·excel
蔚一44 分钟前
Java设计模式—面向对象设计原则(三) -----> 依赖倒转原则DIP(完整详解,附有代码+案例)
java·开发语言·设计模式·intellij-idea·依赖倒置原则