Sam*_*ina 1 c multithreading struct pthreads
我有以下代码,简化后只显示相关部分.
我的问题是,在一台机器上它正确显示了线程号和所有其他值,但是当我在其他机器上运行它时,它显示了所有创建的线程的相同值.
我用-lpthread编译它,我甚至尝试静态编译它但结果相同.
为什么它在一台机器上正常工作而在另一台机器上却没有?这是编码错误还是我必须在编译时更改库?我被卡住了.谢谢!
pthread_mutex_t word_list;
struct words_list {
char myword[20];
struct words_list * next;
};
struct arg_struct {
char *myword;
int t;
};
char myword[20];
struct words_list * first_word = NULL;
//the loading data into struct code is missing from here
struct words_list * curr_word = first_word;
pthread_mutex_init(&word_list,NULL);
int ex = 0;
while(curr_word != NULL)
{
struct arg_struct args;
int ret = -1;
for(i = 0 ; i < max_thread; i++)
{
pthread_mutex_lock(&word_list);
strncpy(myword,curr_word->myword,sizeof(myword) - 1);
pthread_mutex_unlock(&word_list);
args.myword = myword;
args.t = i;
//start threads
if(pthread_create(&thread_id[i],NULL,&do_repl,&args) != 0)
{
i--;
fprintf(stderr,RED "\nError in creating thread\n" NONE);
}
else
{
pthread_mutex_lock(&word_list);
if(curr_word->next == NULL)
ex = 1;
else
curr_word = curr_word->next;
pthread_mutex_unlock(&word_list);
}
}//end threads creating
for(i = 0 ; i < max_thread; i++)
{
void *join_result;
if(pthread_join(thread_id[i],&join_result) != 0)
fprintf(stderr,RED "\nError in joining thread\n" NONE);
else
{
ret = *(int *)join_result;
free(join_result);
if((ret == 1)
{
ex = 1;
break;
}
}
}//end threads joining
if (ex == 1)
break;
}//end while
void* do_repl(void *arguments)
{
int *res = malloc(sizeof(int));
struct arg_struct *args = arguments;
char *word = args->word;
int t = args->t;
fprintf(stderr,"(%d) word: %s\n",t,word);
*res = 0;
return res;
}
Run Code Online (Sandbox Code Playgroud)
从arg结构开始,此代码中存在多个问题.所有线程都共享相同的逻辑arg结构,其中包括严重的竞争条件:
struct arg_struct args; // << == Note. Local variable.
int ret = -1;
for(i = 0 ; i < max_thread; i++)
{
pthread_mutex_lock(&word_list);
strncpy(myword,curr_word->myword,sizeof(myword) - 1);
pthread_mutex_unlock(&word_list);
args.myword = myword;
args.t = i;
//start threads NOTE: args passed by address.
if(pthread_create(&thread_id[i],NULL,&do_repl,&args) != 0)
{
i--;
fprintf(stderr,RED "\nError in creating thread\n" NONE);
}
// rest of code...
}
Run Code Online (Sandbox Code Playgroud)
现在想一想当该线程启动时会发生什么.如果你的for循环在其中一些线程有机会访问该arg-stuct并拉出它们的特定线程信息之前启动多个线程,那么这些线程将访问你保存在其中的最后一个数据,这将是最后一次迭代循环(如果你真的很不走运,你可能会在更新中找到它,但我不会深入到这个级别的细节;这一点应该是显而易见的).
我建议你动态分配线程参数结构,让线程在完成后销毁它.作为一个高度建议的替代(并且通常已经完成)使用它作为您的返回值pthread_join,然后main()在提取线程完成数据后销毁它.
其次,你的args结构使用一个指针,为每个线程(局部变量)myword设置相同的缓冲区char myword[20].因此,即使您将参数结构"修复"为动态,您仍然可以使用相同的缓冲区.
解
动态分配每个线程的参数结构.在其中,有一个正在处理的单词的本地副本.同样,存储args将传递给那里的线程的返回代码(省去了必须在线程中分配一个并释放它的麻烦main()).
// thread arguments.
struct arg_struct
{
char myword[20];
int ret;
int t;
};
Run Code Online (Sandbox Code Playgroud)
在你的线程启动循环中:
while(curr_word != NULL)
{
int ret = -1;
for(i = 0 ; i < max_thread; i++)
{
// allocate a new argument struct for the new thread
struct arg_struct *args = calloc(1, sizeof(*args));
args->t = i;
// this lock is pointless, btw.
pthread_mutex_lock(&word_list);
strcpy(args->myword, cur_word->myword); //note: assumes no overrun.
pthread_mutex_unlock(&word_list);
//start threads
if(pthread_create(&thread_id[i],NULL, &do_repl, args) != 0)
{
i--;
fprintf(stderr,RED "\nError in creating thread\n" NONE);
}
else
{
pthread_mutex_lock(&word_list);
if(curr_word->next == NULL)
ex = 1;
else
curr_word = curr_word->next;
pthread_mutex_unlock(&word_list);
}
}//end threads creating
for(i = 0 ; i < max_thread; i++)
{
void *join_result = NULL;
if(pthread_join(thread_id[i], &join_result) != 0)
fprintf(stderr,RED "\nError in joining thread\n" NONE);
else
{
ret = ((struct arg_struct*)join_result)->ret;
free(join_result);
if((ret == 1)
{
ex = 1;
break;
}
}
}//end threads joining
if (ex == 1)
break;
}//end while
Run Code Online (Sandbox Code Playgroud)
在线程proc中,只需执行以下操作:
void* do_repl(void *arguments)
{
struct arg_struct *args = arguments;
fprintf(stderr,"(%d) word: %s\n", args->t, args->word);
args->ret = 0;
return args;
}
Run Code Online (Sandbox Code Playgroud)
对不起我可能留下的任何错别字,但我希望你明白这一点.
编辑 OP请求了一个简单的线程示例,它使用自定义参数块启动线程.以下内容就是将实际的链表直接暴露给线程组.线程都共享一个公共指针(通过地址,因此指向指针的指针),它最初指向列表头,并由互斥锁(线程也共享)保护.所有线程一直运行,直到它们检测到列表为空,此时它们退出.这意味着你可以加载列表比你的游泳池显著大名单(我选择了5点的池,20的名单,但你可以有许多在列表中比这更多的条目).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
typedef struct node
{
char myword[20];
struct node *next;
} node;
// thread arguments.
typedef struct arg_struct
{
pthread_mutex_t *mtx;
node **pp;
int ret;
int t;
} arg_struct;
// thread procedure. doesn't do much
void* do_repl(void *arguments)
{
arg_struct *args = arguments;
while (1)
{
// lock, get, and unlock
pthread_mutex_lock(args->mtx);
node *p = *args->pp;
if (p)
{
*args->pp = p->next;
pthread_mutex_unlock(args->mtx);
// print the node we just got from the list.
fprintf(stderr,"(%d) word: %s\n", args->t, p->myword);
}
else
{
// no more entries in list. break
break;
}
};
// make sure this is released
pthread_mutex_unlock(args->mtx);
args->ret = 0;
return args;
}
// main entrypoint.
int main()
{
// very simple. we use a fixed number of threads and list nodes.
static const int n_threads = 5;
// build a simple forward-only linked list. will have 4x the
// number of threads in our crew.
node *list = NULL;
node **next = &list;
int i = 0;
for (i=0;i<n_threads*4;++i)
{
node *p = malloc(sizeof(*p));
sprintf(p->myword, "String-%d", i+1);
*next = p;
next = &(p->next);
}
*next = NULL;
// declare a mutex and thread pool for hitting all the elements
// in the linked list.
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_t threads[n_threads];
// lock the mutex before creating the thread pool.
pthread_mutex_lock(&mtx);
i = 0;
node *shared = list;
for (int i=0; i<n_threads; ++i)
{
// setup some thread arguments.
arg_struct *args = calloc(1, sizeof(*args));
args->mtx = &mtx;
args->pp = &shared;
args->t = i+1;
// launch the thread.
pthread_create(threads + i, NULL, do_repl, args);
}
// now unlatch the mutex and wait for the threads to finish.
pthread_mutex_unlock(&mtx);
for (i=0;i<n_threads;++i)
{
void *pv = NULL;
pthread_join(threads[i], &pv);
arg_struct *args = pv;
fprintf(stderr,"Thread %d finished\n", args->t);
free(args);
}
// cleanup the linked list.
while (list != NULL)
{
node *p = list;
list = list->next;
free(p);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出(因系统和运行实例而异)
(2) word: String-2
(1) word: String-1
(3) word: String-3
(4) word: String-4
(5) word: String-5
(2) word: String-6
(1) word: String-7
(3) word: String-8
(4) word: String-9
(5) word: String-10
(2) word: String-11
(1) word: String-12
(3) word: String-13
(4) word: String-14
(2) word: String-16
(1) word: String-17
(5) word: String-15
(3) word: String-18
(4) word: String-19
(2) word: String-20
Thread 1 finished
Thread 2 finished
Thread 3 finished
Thread 4 finished
Thread 5 finished
Run Code Online (Sandbox Code Playgroud)
请注意报告每个字符串的线程ID.这证明每个线程在列表上消耗多个条目,但每个线程只有一个线程.参数块中的共享指针确保了这一点(以及明显的互斥保护).
| 归档时间: |
|
| 查看次数: |
905 次 |
| 最近记录: |