两个线程同步执行:解决乱箭穿心(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

相关推荐
Abladol-aj6 分钟前
并发和并行的基础知识
java·linux·windows
Elihuss1 小时前
ONVIF协议操作摄像头方法
开发语言·php
Swift社区4 小时前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
没头脑的ht5 小时前
Swift内存访问冲突
开发语言·ios·swift
没头脑的ht5 小时前
Swift闭包的本质
开发语言·ios·swift
JunLan~5 小时前
Rocky Linux 系统安装/部署 Docker
linux·docker·容器
wjs20245 小时前
Swift 数组
开发语言
南东山人5 小时前
一文说清:C和C++混合编程
c语言·c++
方竞6 小时前
Linux空口抓包方法
linux·空口抓包
stm 学习ing6 小时前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga