【问题标题】:C pthread allow only four threads to execute functionC pthread 只允许四个线程执行函数
【发布时间】:2016-10-01 21:12:39
【问题描述】:

这里有个问题,假设我需要执行一个函数 x 次来执行一些任务,但在任何给定时间只有 四个 线程可以执行它。所以线程A、B、C、D可以分别启动任务0、1、2、3。但是,任务四在其中一个线程完成之前无法启动,因此假设线程 A 完成,那么下一个任务可以由其中一个空闲线程执行。这应该重复 x 次,其中 x 是函数需要被调用的次数。

所以我使用了信号量并在它完成后加入 pthread 以确保它完成。但是,有时 main 函数在某些线程完成之前完成执行,并且 valgrind 抱怨我的 pthread_create 正在泄漏内存。我认为我正在做的方式不正确或者是一种天真的方法,因此任何解决此问题的指导或示例代码将不胜感激!这是我的代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <time.h>
    #include <pthread.h>
    #include <semaphore.h>

    sem_t s;
    typedef struct Data Data;
    struct Data {
        pthread_t* a;
        int index;
        int j; 
    };
    void* someFunction(void* arg){ 
        /* Only at most num_threads should be here at once; */
        sem_wait(&s);
        Data* d = arg;
        printf("Successfully completed task %d with thread %d\n", d->index, d->j);
        sleep(2);   
        pthread_t* z = d->a;
        free(d);
        pthread_join(*z, NULL);
        sem_post(&s);
        return 0;
    }  
    int main(void){
        int num_task = 15; // i need to call someFunction() 9000 times
        int num_threads = 4; 
        int j = 0;
        sem_init(&s, 0, num_threads);
        pthread_t thread_ids[num_threads];
        for (int i = 0; i < num_task; i ++){ 
            /*NEED TO COMPLETE num_tasks using four threads;
            4 threads can run someFunction() at the same time; so one all four are currently executing someFunction(), other threads can't enter until one has completed. */
            if (j == num_threads){
                j = 0; // j goes 0 1 2 3 0 1 2 3 ...
            }
            Data* a = malloc(sizeof(Data));
            a->a = thread_ids + j;
            a->index = i;
            a->j = j;
            sem_wait(&s);
            pthread_create(thread_ids + j, NULL, someFunction, a);
            sem_post(&s); 
            j ++;
        }
        return 0;
    }

非常感谢

【问题讨论】:

  • 第一个创建线程会尝试加入自己。这是一个僵局。

标签: c concurrency pthreads semaphore


【解决方案1】:

让线程相互等待通常很快就会变得混乱,并且您很可能会遇到线程尝试加入自身或从未加入的情况。

最多运行四个线程的最可靠方法是只创建四个线程。
您无需根据需要创建线程,而是让每个线程(可能)执行多个任务。

您可以将“任务”概念与“线程”概念分开:

  • 为要执行的线程创建一个任务队列。
  • 创建四个线程。
  • 每个线程从队列中获取一个任务并执行它,重复执行直到队列为空。
  • 等待main 中的线程完成。

唯一需要同步的就是从队列中移除一个任务,这很简单。
(如果任务不独立,则需要更复杂的管道。)

伪代码(我发明了一些名称,因为我对 pthread 不太熟悉):

typedef struct Task
{
    /* whatever */  
};

/* Very simplistic queue structure. */
typedef struct Queue
{
    mutex lock;
    int head;
    Task tasks[num_tasks];
};

/* Return front of queue; NULL if empty. */
Task* dequeue(Queue* q)
{
    Task* t = NULL;
    lock_mutex(q->lock);
    if (q->head < num_tasks)
    {
        t = &q->tasks[q->head];
        q->head++;
    }
    unlock_mutex(q->lock);
    return t;
}

/* The thread function is completely unaware of any multithreading
   and can be used in a single-threaded program while debugging. */ 
void* process(void* arg)
{
    Queue* queue = (Queue*) arg;
    for (;;)
    {
        Task* t = dequeue(queue);
        if (!t)
        {
            /* Done. */
            return NULL;
        }
        /* Perform task t */
    }
}

/* main is very simple - set up tasks, launch threads, wait for threads.
   No signalling, no memory allocation. */
int main(void)
{
    pthread threads[num_threads];
    Queue q;
    q.head = 0;
    /* Fill in q.tasks... */
    /* Initialise q.lock... */

    for (int ti = 0; ti < num_threads; ti++)
    {
        pthread_create(threads + ti, NULL, process, &q);
    }
    for (int ti = 0; ti < num_threads; ti++)
    {
        /* join the thread */
    }

    return 0;
}

【讨论】:

  • '最多运行四个线程的最可靠方法是只创建四个线程'哈哈,这一切都是真的,但我怀疑 OP 是否愿意提供这么好的解决方案:)
【解决方案2】:

您的代码一次启动四个线程并等待它们完成。但是,您的主循环仅创建线程,不会让它们退出。 创建线程后,您的操作系统将随时安排它。

这意味着您必须加入您在 for 循环之后创建的最后四个线程。所以他们有机会完成他们的工作并释放他们的记忆。

问候

【讨论】:

    猜你喜欢
    • 2012-04-27
    • 2021-03-01
    • 2017-01-09
    • 1970-01-01
    • 2023-01-16
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多