是否有任何机制可以让我在不通过内核的情况下唤醒另一个进程中的线程?等待线程可能在循环中旋转,没有问题(每个线程都挂在一个单独的核心),但在我的情况下,发送线程必须很快,并且不能通过内核来唤醒等待的线程
答案 0 :(得分:4)
不,如果另一个线程正在休眠(不在CPU上)。要唤醒这样的线程,你需要通过调用作为内核一部分的调度程序将其状态更改为“RUNNING”。
是的,如果两个线程或进程在不同的CPU上运行,并且它们之间存在共享内存,则可以同步两个线程或进程。您应该将所有线程绑定到不同的CPU。然后你可以使用来自POSIX的Pthread('(ADVANCED REALTIME THREADS)'
; [THR SPI]
)的可选部分的spinlock:pthread_spin_lock
和pthread_spin_unlock
函数;或任何自定义螺旋锁。自定义螺旋锁很可能会使用一些原子操作和/或内存障碍。
发送线程将更改内存中的值,该值由接收方线程在循环中检查。
E.g。
INIT:
pthread_spinlock_t lock;
pthread_spin_lock(&lock); // close the "mutex"
然后启动线程。
等待线程:
{
pthread_spin_lock(&lock); // wait for event;
work();
}
主线程:
{
do_smth();
pthread_spin_unlock(&lock); // open the mutex; other thread will see this change
// in ~150 CPU ticks (checked on Pentium4 and Intel Core2 single socket systems);
// time of the operation itself is of the same order; didn't measure it.
continue_work();
}
答案 1 :(得分:1)
向另一个进程发出信号表明它应该继续,而不强迫发送者花时间在内核调用中,立即想到一种机制。没有内核调用,所有进程都可以做的就是修改内存;所以解决方案是inter-process shared memory。一旦发送方写入共享内存,接收方应该看到更改而没有任何明确的内核调用,接收方的天真轮询应该可以正常工作。
一个便宜的(但可能不够便宜)替代方案是将发送委托给同一进程中的帮助程序线程,并让帮助程序线程进行正确的进程间“信号量释放”或管道写入调用。
答案 2 :(得分:0)
我知道您要避免使用内核以避免与内核相关的开销。大多数此类开销与上下文切换相关。下面是一种演示如何使用信号而无需旋转,无需上下文切换的方法:
#include <signal.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <pthread.h>
#include <iostream>
#include <thread>
using namespace std;
void sigRtHandler(int sig) {
cout << "Recevied signal" << endl;
}
int main() {
constexpr static int kIter = 100000;
thread t([]() {
signal(SIGRTMIN, sigRtHandler);
for (int i = 0; i < kIter; ++i) {
usleep(1000);
}
cout << "Done" << endl;
});
usleep(1000); // Give child time to setup signal handler.
auto handle = t.native_handle();
for (int i = 0; i < kIter; ++i)
pthread_kill(handle, SIGRTMIN);
t.join();
return 0;
}
如果运行此代码,您将看到子线程继续接收SIGRTMIN。当进程正在运行时,如果查看此进程的文件/ proc /(PID)/ task / * / status,您将看到父线程不会因调用pthread_kill()而导致上下文切换。
这种方法的优点是等待线程不需要旋转。如果等待线程的作业不是时间敏感的,则此方法允许您节省CPU。