I cannot find a proper solution to my problem.
我找不到合适的方法来解决我的问题。
If i have more than one thread in one process. And I want to make only one thread to sleep while running the other threads within the same process, is there any predefined syntax for it or do i have to do my own implementation (sleep) ?
如果一个过程中有多个线程。在运行同一进程中的其他线程时,我只希望让一个线程休眠,是否有预定义的语法,或者我是否必须执行自己的实现(sleep) ?
Ideally i want to send a indication from a thread to another thread when it is time for sleep.
理想情况下,我希望在睡眠时间从线程发送指示到另一个线程。
Edited (2015-08-24) I have two main threads, one for sending data over a network, the other receives the data from the network. Beside jitter, the receiving thread does validation and verification and some file management which in time could lead that it will drag behind. What i like to do is to add something like a micro sleep to the sender so that the receiver could catch up. sched_yield() will not help in this case because the HW has a multi core CPU with more than 40 cores.
我有两个主要线程,一个用于通过网络发送数据,另一个用于从网络接收数据。除了抖动之外,接收线程还进行验证和文件管理,这可能会导致它被拖到后面。我喜欢做的是给发送者添加一些像微睡眠这样的东西,这样接收者就能赶上来。sched_yield()在这种情况下不会有帮助,因为HW具有超过40个内核的多核CPU。
1 个解决方案
#1
2
From your description in the comments, it looks like you're trying to synchronize 2 threads so that one of them doesn't fall behind too far from the other.
从您在评论中的描述来看,看起来您正在尝试同步两个线程,以便其中一个线程不会落后于另一个线程。
If that's the case, you're going about this the wrong way. It is seldom a good idea to do synchronization by sleeping, because the scheduler may incur unpredictable and long delays that cause the other (slow) thread to remain stopped in the run queue without being scheduled. Even if it works most of the time, it's still a race condition, and it's an ugly hack.
如果是这样的话,你就错了。通过睡眠进行同步很少是一个好主意,因为调度器可能会导致不可预知的长时间延迟,从而导致另一个(慢)线程在运行队列中保持停止而不被调度。即使它在大多数情况下都有效,它仍然是一种竞争状态,而且是一种丑陋的黑客行为。
Given your use case and constraints, I think you'd be better off using barriers (see pthread_barrier_init(3)
). Pthread barriers allow you to create a rendezvous point in the code where threads can catch up.
考虑到您的用例和约束,我认为您最好使用barrier(参见pthread_barrier_init(3))。Pthread屏障允许您在代码中创建一个集合点,在那里线程可以赶上。
You call pthread_barrier_init(3)
as part of the initialization code, specifying the number of threads that will be synchronized using that barrier. In this case, it's 2.
作为初始化代码的一部分,您可以调用pthread_barrier_init(3),指定使用该barrier进行同步的线程数量。这里是2。
Then, threads synchronize with others by calling pthread_barrier_wait(3)
. The call blocks until the number of threads specified in pthread_barrier_init(3)
call pthread_barrier_wait(3)
, at which point every thread that was blocked in pthread_barrier_wait(3)
becomes runnable and the cycle begins again. Essentially, barriers create a synchronization point where no one can move forward until everyone arrives. I think this is exactly what you're looking for.
然后,线程通过调用pthread_barrier_wait(3)与其他线程同步。调用会阻塞,直到pthread_barrier_init(3)中指定的线程数量调用pthread_barrier_wait(3),此时,pthread_barrier_wait(3)中阻塞的每个线程都可运行,循环再次开始。实质上,障碍创建了一个同步点,在每个人到达之前,没有人可以向前移动。我想这正是你想要的。
Here's an example that simulates a fast sender thread and a slow receiver thread. They both synchronize with barriers to ensure that the sender does not do any work while the receiver is still processing other requests. The threads synchronize at the end of their work unit, but of course, you can choose where each thread calls pthread_barrier_wait(3)
, thereby controlling exactly when (and where) threads synchronize.
这是一个模拟快速发送者线程和慢接收线程的示例。它们都与屏障同步,以确保发送方在接收方仍在处理其他请求时不做任何工作。线程在其工作单元的末尾同步,但是当然,您可以选择每个线程调用pthread_barrier_wait(3)的位置,从而精确地控制线程何时(以及在何处)同步。
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
pthread_barrier_t barrier;
void *sender_thr(void *arg) {
printf("Entered sender thread\n");
int i;
for (i = 0; i < 10; i++) {
/* Simulate some work (500 ms) */
if (usleep(500000) < 0) {
perror("usleep(3) error");
}
printf("Sender thread synchronizing.\n");
/* Wait for receiver to catch up */
int barrier_res = pthread_barrier_wait(&barrier);
if (barrier_res == PTHREAD_BARRIER_SERIAL_THREAD)
printf("Sender thread was last.\n");
else if (barrier_res == 0)
printf("Sender thread was first.\n");
else
fprintf(stderr, "pthread_barrier_wait(3) error on sender: %s\n", strerror(barrier_res));
}
return NULL;
}
void *receiver_thr(void *arg) {
printf("Entered receiver thread\n");
int i;
for (i = 0; i < 10; i++) {
/* Simulate a lot of work */
if (usleep(2000000) < 0) {
perror("usleep(3) error");
}
printf("Receiver thread synchronizing.\n");
/* Catch up with sender */
int barrier_res = pthread_barrier_wait(&barrier);
if (barrier_res == PTHREAD_BARRIER_SERIAL_THREAD)
printf("Receiver thread was last.\n");
else if (barrier_res == 0)
printf("Receiver thread was first.\n");
else
fprintf(stderr, "pthread_barrier_wait(3) error on receiver: %s\n", strerror(barrier_res));
}
return NULL;
}
int main(void) {
int barrier_res;
if ((barrier_res = pthread_barrier_init(&barrier, NULL, 2)) != 0) {
fprintf(stderr, "pthread_barrier_init(3) error: %s\n", strerror(barrier_res));
exit(EXIT_FAILURE);
}
pthread_t threads[2];
int thread_res;
if ((thread_res = pthread_create(&threads[0], NULL, sender_thr, NULL)) != 0) {
fprintf(stderr, "pthread_create(3) error on sender thread: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
if ((thread_res = pthread_create(&threads[1], NULL, receiver_thr, NULL)) != 0) {
fprintf(stderr, "pthread_create(3) error on receiver thread: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
/* Do some work... */
if ((thread_res = pthread_join(threads[0], NULL)) != 0) {
fprintf(stderr, "pthread_join(3) error on sender thread: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
if ((thread_res = pthread_join(threads[1], NULL)) != 0) {
fprintf(stderr, "pthread_join(3) error on receiver thread: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
if ((barrier_res = pthread_barrier_destroy(&barrier)) != 0) {
fprintf(stderr, "pthread_barrier_destroy(3) error: %s\n", strerror(barrier_res));
exit(EXIT_FAILURE);
}
return 0;
}
Note that, as specified in the manpage for pthread_barrier_wait(3)
, once the desired number of threads call pthread_barrier_wait(3)
, the barrier state is reset to the original state that was in use after the last call to pthread_barrier_init(3)
, which means that the barrier atomically unlocks and resets state, so it is always ready for the next synchronization point, which is wonderful.
注意,在从指定pthread_barrier_wait(3),一旦所需数量的线程调用pthread_barrier_wait(3),障碍状态重置到原始状态,在使用后调用pthread_barrier_init(3),这意味着障碍自动解锁和重置状态,所以它总是准备好下一个同步点,这是美妙的。
Once you're done with the barrier, don't forget to free the associated resources with pthread_barrier_destroy(3)
.
一旦完成了barrier,不要忘记使用pthread_barrier_destroy(3)释放相关的资源。
#1
2
From your description in the comments, it looks like you're trying to synchronize 2 threads so that one of them doesn't fall behind too far from the other.
从您在评论中的描述来看,看起来您正在尝试同步两个线程,以便其中一个线程不会落后于另一个线程。
If that's the case, you're going about this the wrong way. It is seldom a good idea to do synchronization by sleeping, because the scheduler may incur unpredictable and long delays that cause the other (slow) thread to remain stopped in the run queue without being scheduled. Even if it works most of the time, it's still a race condition, and it's an ugly hack.
如果是这样的话,你就错了。通过睡眠进行同步很少是一个好主意,因为调度器可能会导致不可预知的长时间延迟,从而导致另一个(慢)线程在运行队列中保持停止而不被调度。即使它在大多数情况下都有效,它仍然是一种竞争状态,而且是一种丑陋的黑客行为。
Given your use case and constraints, I think you'd be better off using barriers (see pthread_barrier_init(3)
). Pthread barriers allow you to create a rendezvous point in the code where threads can catch up.
考虑到您的用例和约束,我认为您最好使用barrier(参见pthread_barrier_init(3))。Pthread屏障允许您在代码中创建一个集合点,在那里线程可以赶上。
You call pthread_barrier_init(3)
as part of the initialization code, specifying the number of threads that will be synchronized using that barrier. In this case, it's 2.
作为初始化代码的一部分,您可以调用pthread_barrier_init(3),指定使用该barrier进行同步的线程数量。这里是2。
Then, threads synchronize with others by calling pthread_barrier_wait(3)
. The call blocks until the number of threads specified in pthread_barrier_init(3)
call pthread_barrier_wait(3)
, at which point every thread that was blocked in pthread_barrier_wait(3)
becomes runnable and the cycle begins again. Essentially, barriers create a synchronization point where no one can move forward until everyone arrives. I think this is exactly what you're looking for.
然后,线程通过调用pthread_barrier_wait(3)与其他线程同步。调用会阻塞,直到pthread_barrier_init(3)中指定的线程数量调用pthread_barrier_wait(3),此时,pthread_barrier_wait(3)中阻塞的每个线程都可运行,循环再次开始。实质上,障碍创建了一个同步点,在每个人到达之前,没有人可以向前移动。我想这正是你想要的。
Here's an example that simulates a fast sender thread and a slow receiver thread. They both synchronize with barriers to ensure that the sender does not do any work while the receiver is still processing other requests. The threads synchronize at the end of their work unit, but of course, you can choose where each thread calls pthread_barrier_wait(3)
, thereby controlling exactly when (and where) threads synchronize.
这是一个模拟快速发送者线程和慢接收线程的示例。它们都与屏障同步,以确保发送方在接收方仍在处理其他请求时不做任何工作。线程在其工作单元的末尾同步,但是当然,您可以选择每个线程调用pthread_barrier_wait(3)的位置,从而精确地控制线程何时(以及在何处)同步。
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
pthread_barrier_t barrier;
void *sender_thr(void *arg) {
printf("Entered sender thread\n");
int i;
for (i = 0; i < 10; i++) {
/* Simulate some work (500 ms) */
if (usleep(500000) < 0) {
perror("usleep(3) error");
}
printf("Sender thread synchronizing.\n");
/* Wait for receiver to catch up */
int barrier_res = pthread_barrier_wait(&barrier);
if (barrier_res == PTHREAD_BARRIER_SERIAL_THREAD)
printf("Sender thread was last.\n");
else if (barrier_res == 0)
printf("Sender thread was first.\n");
else
fprintf(stderr, "pthread_barrier_wait(3) error on sender: %s\n", strerror(barrier_res));
}
return NULL;
}
void *receiver_thr(void *arg) {
printf("Entered receiver thread\n");
int i;
for (i = 0; i < 10; i++) {
/* Simulate a lot of work */
if (usleep(2000000) < 0) {
perror("usleep(3) error");
}
printf("Receiver thread synchronizing.\n");
/* Catch up with sender */
int barrier_res = pthread_barrier_wait(&barrier);
if (barrier_res == PTHREAD_BARRIER_SERIAL_THREAD)
printf("Receiver thread was last.\n");
else if (barrier_res == 0)
printf("Receiver thread was first.\n");
else
fprintf(stderr, "pthread_barrier_wait(3) error on receiver: %s\n", strerror(barrier_res));
}
return NULL;
}
int main(void) {
int barrier_res;
if ((barrier_res = pthread_barrier_init(&barrier, NULL, 2)) != 0) {
fprintf(stderr, "pthread_barrier_init(3) error: %s\n", strerror(barrier_res));
exit(EXIT_FAILURE);
}
pthread_t threads[2];
int thread_res;
if ((thread_res = pthread_create(&threads[0], NULL, sender_thr, NULL)) != 0) {
fprintf(stderr, "pthread_create(3) error on sender thread: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
if ((thread_res = pthread_create(&threads[1], NULL, receiver_thr, NULL)) != 0) {
fprintf(stderr, "pthread_create(3) error on receiver thread: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
/* Do some work... */
if ((thread_res = pthread_join(threads[0], NULL)) != 0) {
fprintf(stderr, "pthread_join(3) error on sender thread: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
if ((thread_res = pthread_join(threads[1], NULL)) != 0) {
fprintf(stderr, "pthread_join(3) error on receiver thread: %s\n", strerror(thread_res));
exit(EXIT_FAILURE);
}
if ((barrier_res = pthread_barrier_destroy(&barrier)) != 0) {
fprintf(stderr, "pthread_barrier_destroy(3) error: %s\n", strerror(barrier_res));
exit(EXIT_FAILURE);
}
return 0;
}
Note that, as specified in the manpage for pthread_barrier_wait(3)
, once the desired number of threads call pthread_barrier_wait(3)
, the barrier state is reset to the original state that was in use after the last call to pthread_barrier_init(3)
, which means that the barrier atomically unlocks and resets state, so it is always ready for the next synchronization point, which is wonderful.
注意,在从指定pthread_barrier_wait(3),一旦所需数量的线程调用pthread_barrier_wait(3),障碍状态重置到原始状态,在使用后调用pthread_barrier_init(3),这意味着障碍自动解锁和重置状态,所以它总是准备好下一个同步点,这是美妙的。
Once you're done with the barrier, don't forget to free the associated resources with pthread_barrier_destroy(3)
.
一旦完成了barrier,不要忘记使用pthread_barrier_destroy(3)释放相关的资源。