线程间通讯(几种常见的通讯机制,以及实例)

线程间通讯是指多个线程之间通过某种机制进行信息交流和共享数据的过程。线程间通讯的目的是为了协调不同线程的工作,使得它们能够有序地执行任务,避免出现竞争条件和数据不一致的问题。

一、常见的线程间通讯机制方式

1、 共享内存

        多个线程共享同一块内存区域,通过读写共享内存来实现信息交流和数据共享。需要考虑线程安全问题,可以使用互斥锁、信号量等机制来保证数据的一致性。

2、信号量

        通过信号量来实现线程之间的同步和互斥。通过P操作和V操作来改变信号量的值,当信号量的值为0时,线程需要等待;当信号量的值大于0时,线程可以继续执行。

3、互斥锁

        通过互斥锁来实现线程之间的互斥访问共享资源。当一个线程获取到互斥锁时,其他线程需要等待;当一个线程释放互斥锁时,其他线程可以竞争获取锁。

4、条件变量

        通过条件变量来实现线程之间的等待和唤醒。当线程需要等待某个条件满足时,可以调用条件变量的等待函数使自己进入等待状态;当条件满足时,可以调用条件变量的唤醒函数唤醒等待的线程。

5、管道

        通过管道来实现线程之间的通信。一个线程可以将数据写入管道,另一个线程可以从管道中读取数据。需要注意管道的大小限制和线程安全问题。

6、postThreadMessage(MFC)

      PostThreadMessage是一个Windows API函数,用于向指定线程的消息队列中发送一个消息.。

以上是常见的几种线程间通讯机制,不同的场景和需求可能需要选择不同的机制来实现线程间的通讯。

二、进程间通讯的实例

1、互斥锁(mutex)和条件变量(condition_variable)
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;
int val = 0;

void producer()
{
    // 模拟生产者生产数据的耗时操作:让当前线程暂停执行 2 秒钟
    std::this_thread::sleep_for(std::chrono::seconds(2)); 
    std::lock_guard<std::mutex> lock(mtx);// 在作用域中加锁
    val = 42;
    ready = true;
    cv.notify_one(); // 唤醒等待的线程
}// 在作用域结束时自动解锁

void consumer()
{
    std::cout << "Consumer is waiting for data..." << std::endl;

    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return ready; });// 在满足特定条件之前暂时挂起自己

    std::cout << "Consumer received data: " << val << std::endl;
}

int main()
{
    std::thread t1(producer);
    std::thread t2(consumer);

    t1.join();
    t2.join();

    return 0;
}

std::lock_guard 是C++标准库中的一个模板类,用于保护一个互斥量(mutex)的自动加锁和解锁操作。它是RAII(资源获取即初始化)的一种实现方式。

当创建一个 std::lock_guard 对象时,它会在构造函数中自动调用互斥量的 lock() 方法,获取互斥量的锁。当 std::lock_guard 对象被销毁时,它会在析构函数中自动调用互斥量的 unlock() 方法,释放互斥量的锁。

使用 std::lock_guard 可以确保在作用域结束时互斥量一定会被解锁,避免了因为异常或其他原因导致忘记解锁而造成的死锁问题。

std::condition_variable是C++标准库中定义的一个类,用于多线程编程中的线程同步和互斥操作。它提供了一种线程间的通信机制,允许一个线程等待另一个线程满足特定条件后再继续执行。

具体来说,std::condition_variable可以与std::mutex(互斥锁)配合使用,实现线程的等待和唤醒操作。一个线程可以通过调用std::condition_variable的wait()函数,在满足特定条件之前暂时挂起自己。另一个线程在某个条件满足时,可以通过调用std::condition_variable的notify_one()或notify_all()函数,唤醒等待的线程。

std::condition_variable的使用通常需要和std::unique_lockstd::mutex结合使用,以实现线程安全的条件变量操作。在等待条件时,线程会自动释放持有的互斥锁,使得其他线程可以访问共享资源。当条件满足时,线程会重新获取互斥锁,并继续执行。

总而言之,std::condition_variable提供了一种线程间的协调机制,使得线程可以在特定条件满足时等待或唤醒,从而实现更灵活的线程同步和互斥操作。

在这个示例中,有一个生产者线程和一个消费者线程。生产者线程会在2秒后生成一个数据,并将ready标志设置为true,然后通知消费者线程。消费者线程在收到通知后,输出接收到的数据。

通过互斥锁(mutex)和条件变量(condition_variable),生产者线程在生产数据之前会等待消费者线程准备好。消费者线程在接收到数据之前会等待生产者线程通知。

这样就实现了线程间的通信。

2、postThreadMessage(MFC)

实例可以参考上一篇文章:线程间通讯:PostThreadMessage_Ivy_belief的博客-CSDN博客

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Qt中,线程通讯可以使用共享内存来实现。共享内存是一种跨进程共享数据的机制,可以在不同的线程传递数据。 Qt提供了QSharedMemory类来操作共享内存。下面是一个使用共享内存进行线程通讯的示例: ```cpp // 创建一个共享内存对象 QSharedMemory sharedMemory; // 设置共享内存的名称 sharedMemory.setKey("MySharedMemory"); // 在一个线程中写入数据到共享内存 if (sharedMemory.create(1024)) { sharedMemory.lock(); char* data = static_cast<char*>(sharedMemory.data()); // 在这里写入数据到共享内存 // 注意:要确保多个线程对共享内存的访问是互斥的,可以使用QMutex来实现互斥访问 sharedMemory.unlock(); } // 在另一个线程中读取共享内存中的数据 if (sharedMemory.attach()) { sharedMemory.lock(); char* data = static_cast<char*>(sharedMemory.data()); // 在这里读取共享内存中的数据 sharedMemory.unlock(); sharedMemory.detach(); } ``` 在上面的示例中,我们创建了一个名为"MySharedMemory"的共享内存对象,并设置了它的大小为1024字节。然后,在一个线程中写入数据到共享内存中,另一个线程则可以读取共享内存中的数据。 需要注意的是,在多个线程对共享内存进行读写时,需要确保访问的互斥性,以避免数据竞争。可以使用QMutex或其他同步机制来实现互斥访问。 另外,还可以使用信号与槽机制来实现线程通讯。Qt提供了QObject::moveToThread()方法,可以将一个QObject对象移动到指定的线程中,从而实现线程的信号与槽的连接。这种方式相对于共享内存来说更加方便和安全。 希望以上信息能对你有帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值