即使使用睡眠,线程也不会放弃CPU时间
Threads not relinquishing CPU time even if using sleep
我运行的这个程序有多个线程。三个线程正在为同一父进程生成信号。有四个处理程序线程用于处理由信号生成线程生成的信号。我有一个监控线程,它也接收信号并根据处理。然而,我有一种情况。我可以看出,这些信号并没有平均分配。我的意思是,这些信号指向同一个过程。我有四个处理程序线程和一个监视线程在等待信号。所以他们中的任何人都可以接收到信号。我本来希望它能均匀分布。然而,我可以看到,在这个时候,处理程序线程会接收到一整串信号。就在下一次监视线程处理整个突发信号时。为什么不统一。在处理程序/监视器线程完成对一个信号的处理后,我添加了一个睡眠调用。因此,一旦处理程序/监视器完成一个信号,它就应该给另一个机会来处理下一个信号。然而,输出没有显示的情况
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <cstdio>
#include <stdlib.h>
#define NUM_SENDER_PROCESSES 3
#define NUM_HANDLER_PROCESSES 4
#define NUM_SIGNAL_REPORT 10
#define MAX_SIGNAL_COUNT 100000
using namespace std;
volatile int usrsig1_handler_count = 0;
int usrsig2_handler_count = 0;
int usrsig1_sender_count = 0;
int usrsig2_sender_count = 0;
int monitor_count = 0;
int usrsig1_monitor_count = 0;
int usrsig2_monitor_count = 0;
double time_1[10];
double time_2[10];
int lock_1 = 0;
int lock_2 = 0;
int lock_3 = 0;
int lock_4 = 0;
int lock_5 = 0;
double timestamp() {
struct timeval tp;
gettimeofday(&tp, NULL);
return (double)tp.tv_sec + tp.tv_usec / 1000000.;
}
void sleepMs(double seconds) {
usleep((unsigned int)(seconds*1000000));
}
void *senderfunc(void *parm) {
srand(time(0));
while(true) {
int signal_id = rand()%2 + 1;
if(signal_id == 1) {
while(__sync_lock_test_and_set(&lock_3,1) != 0) {
}
usrsig1_sender_count++;
lock_3 = 0;
kill(getpid(), SIGUSR1);
} else {
while(__sync_lock_test_and_set(&lock_4,1) != 0) {
}
usrsig2_sender_count++;
lock_4 = 0;
kill(getpid(), SIGUSR2);
}
int r = rand()%10 + 1;
double s = (double)r/100;
sleepMs(s);
}
}
void *handlerfunc(void *parm)
{
int *index = (int *)parm;
sigset_t set;
sigemptyset(&set);
//cout << (*index) << endl;
if((*index) % 2 == 0) {
sigaddset(&set, SIGUSR1);
} else {
sigaddset(&set, SIGUSR2);
}
int sig;
while(true) {
sigwait(&set, &sig);
//cout << "Handler" << endl;
if (sig == SIGUSR1) {
while(__sync_lock_test_and_set(&lock_1,1) != 0) {
}
usrsig1_handler_count++;
lock_1 = 0;
} else if(sig == SIGUSR2) {
while(__sync_lock_test_and_set(&lock_2,1) != 0) {
}
usrsig2_handler_count++;
lock_2 = 0;
}
sleepMs(0.0001);
}
}
void *monitorfunc(void *parm) {
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
int sig;
while(true) {
sigwait(&set, &sig);
//cout << "Monitor" << endl;
if(sig == SIGUSR1) {
time_1[usrsig1_monitor_count] = timestamp();
usrsig1_monitor_count++;
} else if(sig == SIGUSR2) {
time_2[usrsig2_monitor_count] = timestamp();
usrsig2_monitor_count++;
}
monitor_count++;
//cout << monitor_count << endl;
if(monitor_count == NUM_SIGNAL_REPORT) {
double difference_1 = 0;
double difference_2 = 0;
if(usrsig1_monitor_count > 1) {
for(int i=0; i<usrsig1_monitor_count-1; i++) {
difference_1 = difference_1 + time_1[i+1] - time_1[i];
}
cout << "Interval SIGUSR1 = " << difference_1/(usrsig1_monitor_count-1)<< endl;
}
if(usrsig2_monitor_count > 1) {
for(int i=0; i<usrsig2_monitor_count-1; i++) {
difference_2 = difference_2 + time_2[i+1] - time_2[i];
}
cout << "Interval SIGUSR2 = " << difference_2/(usrsig2_monitor_count-1) << endl;
}
cout << "Count SIGUSR1 = " << usrsig1_sender_count << endl;
cout << "Count SIGUSR2 = " << usrsig2_sender_count << endl;
monitor_count = 0;
usrsig1_monitor_count = 0;
usrsig2_monitor_count = 0;
}
sleepMs(0.001);
}
}
int main(int argc, char **argv)
{
if(argc != 2) {
cout << "Required parameters missing. " << endl;
cout << "Option 1 = 1 which means run for 30 seconds" << endl;
cout << "Option 2 = 2 which means run until 100000 signals" << endl;
exit(0);
}
int option = atoi(argv[1]);
int i;
pthread_t handlers[NUM_HANDLER_PROCESSES];
pthread_t generators[NUM_SENDER_PROCESSES];
pthread_t monitor;
sigset_t set;
sigset_t oldset;
sigemptyset(&oldset);
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
pthread_sigmask(SIG_BLOCK, &set, &oldset);
int handler_mask[4] = {0,1,2,3};
//Initializing the handler threads
for(i=0; i<NUM_HANDLER_PROCESSES; i++) {
pthread_create(&handlers[i], NULL, handlerfunc, (void *)&handler_mask[i]);
}
pthread_create(&monitor, NULL, monitorfunc, NULL);
sleep(5);
for(i=0; i<NUM_SENDER_PROCESSES; i++) {
pthread_create(&generators[i], NULL, senderfunc, NULL);
}
if(option == 1) {
cout << "Option 1 " << endl;
//sleep(30);
while(true){
}
exit(0);
} else {
while(true) {
if((usrsig1_handler_count + usrsig2_handler_count) >= MAX_SIGNAL_COUNT) {
cout << "Count SIGUSR1 = " << usrsig1_handler_count << endl;
cout << "Count SIGUSR2 = " << usrsig2_handler_count << endl;
exit(0);
} else {
pthread_yield();
}
}
}
}
这是我的输出
HandlerHandler
Handler
Handler
Monitor
Monitor
Monitor
Monitor
Monitor
Monitor
Monitor
Monitor
Monitor
Monitor
Monitor
Monitor
Monitor
Monitor
Handler
Handler
Handler
Handler
Handler
Handler
Handler
Handler
Handler
Handler
您可以看到监视器的突发,然后是处理程序的突发。然而,在代码中,一旦处理程序/监视器处理了一个信号并执行sigwait,我就添加了一个睡眠调用,以便将该调用传递给下一个可用线程。然而,这于事无补。我想这应该让它变得统一。然而,静态监视器会被突发并打印。即使在监视器中,我已经在它完成信号的工作后进入睡眠状态
您的代码会出现两个不同的问题,从而得到您所看到的结果。
第一个也是最重要的一个是为每个线程分配一个运行时间片。这个时间片可以被信号或IO中断,但线程将运行直到它完成它的时间片。因此,即使你设置了睡眠——如果睡眠时间小于该线程的时间片,它也不会将执行转移到其他线程。如果我记得在Windows上,这个时间片至少是5ms,但通常是40ms(尽管我可能弄错了数字)。在linux上,这个时间段可能更短,但对于通用linux盒子,我认为是一样的。我曾经在Windows上使用睡眠(0)来放弃时间片。usleep(0)也可以这样做。所以你使用睡眠的方式不会达到你想要的效果。然而,由于您使用pthreads,只需调用pthread_yield即可放弃CPU或sched_yield(),这应该是更好的做法,但谁知道呢。。。
测试输出可能面临的第二个问题是,在多线程环境中,实际上无法直接控制输出到流的字符顺序。如果你真的想让输出井然有序,你需要实现一个单独的线程来进行输出,并使用队列和一些锁定机制(关键部分,互斥锁)或自由锁定机制向i发送消息。
希望这能让你朝着正确的方向
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 在模拟器中使用并集来模拟CPU寄存器有多合适
- 编写一个函数以使用 n 百分比的 CPU 使用率
- 如何禁用 CPU 的无序执行
- CPU 瓶颈;处理具有许多非静态对象的 3D 场景渲染的简单方法
- 分别测量每个线程上花费的 CPU 时间(C++)
- 什么时候最好在子进程中使用 CPU 或 I/O 密集型代码 [ C++ ]
- 在程序运行时监视 VxWorks 中的任务 CPU 利用率
- 对于等待以 std::future wait() 返回的函数的 CPU 使用率或检查标志在循环中休眠一段时间哪个更好?
- 您选择的 CPU 不支持 x86-64 指令集
- 如何降低应用程序的 CPU 使用率?
- 对于 CPU 无法原子操作的类型,std::atomic 有什么意义?
- 如何区分CPU和内存瓶颈?
- 如何以编程方式获取任务管理器进程CPU使用率(不是PerfMon API)
- CPU 如何提供memory_order_acquire保证?
- 一段时间后 CPU 使用率高
- C/C++memcpu基准测试:测量CPU和墙时间
- 高CPU使用率,在API桌面复制中获取帧之间具有不同的超时间隔
- 即使使用睡眠,线程也不会放弃CPU时间
- 放弃 CPU 时间