Linux 多线程,暂停一个线程,同时继续 运行 同一进程中的其他线程
Linux multi-thread, pausing one thread while continue running the other threads within the same process
我找不到合适的方法解决我的问题。
如果我在一个进程中有多个线程。我只想让一个线程休眠,而 运行 同一进程中的其他线程,是否有任何预定义的语法,或者我是否必须自己实现(睡眠)?
理想情况下,我想在睡眠时间从一个线程向另一个线程发送一个指示。
已编辑 (2015-08-24)
我有两个主线程,一个用于通过网络发送数据,另一个从网络接收数据。除了抖动之外,接收线程还进行验证和验证以及一些文件管理,这可能会及时导致它拖延。我喜欢做的是向发送者添加微睡眠之类的东西,以便接收者能够赶上。 sched_yield() 在这种情况下无济于事,因为硬件有一个多核 CPU 超过 40 个内核。
根据您在评论中的描述,您似乎正在尝试同步 2 个线程,以便其中一个线程不会落后于另一个线程太远。
如果是这样,那你就走错了路。通过睡眠进行同步很少是一个好主意,因为调度程序可能会导致不可预测的长时间延迟,导致另一个(慢速)线程在 运行 队列中保持停止状态而没有被调度。即使它在大部分时间都有效,它仍然是一个竞争条件,而且是一个丑陋的 hack。
鉴于您的用例和限制,我认为您最好使用障碍(请参阅 pthread_barrier_init(3)
)。 Pthread 屏障允许您在代码中创建一个线程可以赶上的集合点。
您调用 pthread_barrier_init(3)
作为初始化代码的一部分,指定将使用该屏障同步的线程数。在这种情况下,它是 2.
然后,线程通过调用 pthread_barrier_wait(3)
与其他线程同步。调用阻塞,直到 pthread_barrier_init(3)
调用 pthread_barrier_wait(3)
中指定的线程数,此时在 pthread_barrier_wait(3)
中阻塞的每个线程都变为 运行nable 并且循环再次开始。从本质上讲,障碍创造了一个同步点,在每个人都到达之前没有人可以前进。我想这正是您要找的。
下面是一个模拟快速发送线程和慢速接收线程的示例。它们都与屏障同步,以确保发送方在接收方仍在处理其他请求时不做任何工作。线程在其工作单元结束时同步,但当然,您可以选择每个线程调用的位置 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;
}
请注意,如 pthread_barrier_wait(3)
的联机帮助页中所述,一旦所需数量的线程调用 pthread_barrier_wait(3)
,屏障状态将重置为上次调用后使用的原始状态到pthread_barrier_init(3)
,这意味着屏障以原子方式解锁并重置状态,因此它始终为下一个同步点做好准备,这太棒了。
完成屏障后,不要忘记使用 pthread_barrier_destroy(3)
释放相关资源。
我找不到合适的方法解决我的问题。
如果我在一个进程中有多个线程。我只想让一个线程休眠,而 运行 同一进程中的其他线程,是否有任何预定义的语法,或者我是否必须自己实现(睡眠)?
理想情况下,我想在睡眠时间从一个线程向另一个线程发送一个指示。
已编辑 (2015-08-24) 我有两个主线程,一个用于通过网络发送数据,另一个从网络接收数据。除了抖动之外,接收线程还进行验证和验证以及一些文件管理,这可能会及时导致它拖延。我喜欢做的是向发送者添加微睡眠之类的东西,以便接收者能够赶上。 sched_yield() 在这种情况下无济于事,因为硬件有一个多核 CPU 超过 40 个内核。
根据您在评论中的描述,您似乎正在尝试同步 2 个线程,以便其中一个线程不会落后于另一个线程太远。
如果是这样,那你就走错了路。通过睡眠进行同步很少是一个好主意,因为调度程序可能会导致不可预测的长时间延迟,导致另一个(慢速)线程在 运行 队列中保持停止状态而没有被调度。即使它在大部分时间都有效,它仍然是一个竞争条件,而且是一个丑陋的 hack。
鉴于您的用例和限制,我认为您最好使用障碍(请参阅 pthread_barrier_init(3)
)。 Pthread 屏障允许您在代码中创建一个线程可以赶上的集合点。
您调用 pthread_barrier_init(3)
作为初始化代码的一部分,指定将使用该屏障同步的线程数。在这种情况下,它是 2.
然后,线程通过调用 pthread_barrier_wait(3)
与其他线程同步。调用阻塞,直到 pthread_barrier_init(3)
调用 pthread_barrier_wait(3)
中指定的线程数,此时在 pthread_barrier_wait(3)
中阻塞的每个线程都变为 运行nable 并且循环再次开始。从本质上讲,障碍创造了一个同步点,在每个人都到达之前没有人可以前进。我想这正是您要找的。
下面是一个模拟快速发送线程和慢速接收线程的示例。它们都与屏障同步,以确保发送方在接收方仍在处理其他请求时不做任何工作。线程在其工作单元结束时同步,但当然,您可以选择每个线程调用的位置 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;
}
请注意,如 pthread_barrier_wait(3)
的联机帮助页中所述,一旦所需数量的线程调用 pthread_barrier_wait(3)
,屏障状态将重置为上次调用后使用的原始状态到pthread_barrier_init(3)
,这意味着屏障以原子方式解锁并重置状态,因此它始终为下一个同步点做好准备,这太棒了。
完成屏障后,不要忘记使用 pthread_barrier_destroy(3)
释放相关资源。