C++在多线程程序中执行串行代码

Serial code execution in a multi-threaded program in C++

本文关键字:代码 执行 多线程 程序 C++      更新时间:2023-10-16

问题:在多线程程序中,是否可以保证代码执行一次只能在一个线程中发生?(或近似于此的东西(

具体来说:我有一个控制器 M(它是一个线程(和线程 A、B、C。我希望M能够决定谁应该被允许参选。当线程完成(最终或暂时(时,控制权将转移回 M。

原因:理想情况下,我希望 A、B 和 C 在自己的线程中执行其代码,而其他代码则不运行。这将使每个线程能够在暂停时保留其指令指针和堆栈,当控制器将控制权交还给它们时,从它们离开的地方开始。

我现在正在做什么:我已经编写了一些实际上可以做到这一点的代码 - 但我不喜欢它。

在伪 C 中:

//Controller M
//do some stuff
UnlockMutex(mutex);
do{}while(lockval==0);
LockMutex(mutex);
//continue with other stuff

//Thread A
//The controller currently has the mutex - will release it at UnlockMutex
LockMutex(mutex); 
lockval=1;
//do stuff
UnlockMutex(mutex);

原因

 do{}while(lockval==0);

需要的是当互斥锁解锁时,A 和 M 都会继续。此技巧可确保 A 在 M 可以再次锁定互斥锁之前不会解锁互斥锁,从而允许 A 第二次重新锁定并再次运行(它应该只运行一次(。

做虽然似乎矫枉过正,但可以完成工作。所以我的问题是,有没有更好的方法?

假设你在Windows上运行,你可以尝试查看Fibers。(参见例如 http://developer.amd.com/Pages/1031200677.aspx 或只是谷歌"Windows fibers"。

我怀疑你真的在寻找协程。

检查 Win32 中的"关键部分"。C++11使用另一个术语"lock_guard"。

如何使用 Boost 制作关键部分?

http://en.cppreference.com/w/cpp/thread/lock_guard

您的代码

do{}while(lockval==0);

会消耗您的 CPU 性能。

我假设您正在 linux 下编写 c++ 并使用 pthread API。这是代码,不是那么健壮,但是一个很好的起点。希望对您有用。使用 "g++ test_controller_thread.cpp -pthread -o test_controller_thread" 来制作二进制执行器。

// 3 threads, one for controller, the other two for worker1 and worker2.
// Only one thread can proceed at any time.
// We use one pthread_mutex_t and two pthread_cond_t to guarantee this.
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t g_controller_cond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t g_worker_cond = PTHREAD_COND_INITIALIZER;
void* controller_func(void *arg) {
    printf("entering the controller thread. n");
    // limit the max time the controller can run
    int max_run_time = 5;
    int run_time = 0;
    pthread_mutex_lock(&g_mutex);
    while (run_time++ < max_run_time) {
        printf("controller is waitting.n");
        pthread_cond_wait(&g_controller_cond, &g_mutex);
        printf("controller is woken up.n");
        pthread_cond_signal(&g_worker_cond);
        printf("signal worker to wake up.n");
    }
    pthread_mutex_unlock(&g_mutex);
}
void* worker_func(void *arg) {
    int work_id = *(int*)arg;
    printf("worker %d start.n", work_id);
    pthread_mutex_lock(&g_mutex);
    while (1) {
        printf("worker %d is waitting for controller.n", work_id);
        pthread_cond_wait(&g_worker_cond, &g_mutex);
        printf("worker %d is working.n", work_id);
        pthread_cond_signal(&g_controller_cond);
        printf("worker %d signal the controller.n", work_id);
    }
    pthread_mutex_unlock(&g_mutex);
}
int main() {
    pthread_t controller_thread, worker_thread_1, worker_thread_2;
    int worker_id_1 = 1;
    int worker_id_2 = 2;
    pthread_create(&controller_thread, NULL, controller_func, NULL);
    pthread_create(&worker_thread_1, NULL, worker_func, &worker_id_1);
    pthread_create(&worker_thread_2, NULL, worker_func, &worker_id_2);
    sleep(1);
    printf("nsignal the controller to start all the process.nn");
    pthread_cond_signal(&g_controller_cond);
    pthread_join(controller_thread, NULL);
    pthread_cancel(worker_thread_1);
    pthread_cancel(worker_thread_2);
    return 0;
}