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

时间:2012-05-05 13:37:26

标签: c++ multithreading synchronization

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

具体来说:我有一个控制器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再次重新锁定并再次运行(它应该只运行一次)。

这种做法看起来有点矫枉过正,但确实有效。所以我的问题是,有更好的方法吗?

3 个答案:

答案 0 :(得分:2)

假设您在Windows上运行,您可能会尝试查看Fibers。 (参见例如http://developer.amd.com/Pages/1031200677.aspx或仅谷歌“windows fiber”。)

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

答案 1 :(得分:1)

在Win32中检查“CriticalSection”。 C ++ 11使用另一个术语“lock_guard”。

How do I make a critical section with Boost?

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

您的代码

do{}while(lockval==0);

会耗尽你的CPU性能。

答案 2 :(得分:0)

我认为你在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.\n\n");
    pthread_cond_signal(&g_controller_cond);

    pthread_join(controller_thread, NULL);
    pthread_cancel(worker_thread_1);
    pthread_cancel(worker_thread_2);

    return 0;
}