这是一个问题,例如我需要执行x次执行某项操作的函数,但在任何给定时间只能执行四个线程。因此线程A,B,C,D可以分别启动任务0、1、2、3。但是,任务四要等到其中一个线程完成后才能开始,所以说如果线程A完成了,那么下一个任务可以由一个空闲线程执行。这应该重复x次,其中x是需要调用该函数的次数。
因此,我使用了信号量,并在完成后加入pthread以确保其完成。但是,有时主函数在某些线程完成之前完成执行,并且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;
    }


非常感谢

最佳答案

使线程彼此等待通常会很快变得混乱,并且您很可能最终会遇到线程尝试自行连接或从未连接的情况。

最多运行四个线程的最可靠方法是仅创建四个线程。
不必根据需要创建线程,而是让每个线程(潜在地)执行多个任务。

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


为线程执行任务队列。
创建四个线程。
每个线程从队列中获取一个任务并执行任务,重复执行直到队列为空。
等待线程在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;
}

关于c - C pthread只允许四个线程执行功能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37586657/

10-11 15:14
查看更多