C 主线程和工作线程初始化
我正在用C语言创建一个多线程程序,我遇到了一些麻烦。 这里有创建线程的函数:C 主线程和工作线程初始化,c,multithreading,pthreads,libc,C,Multithreading,Pthreads,Libc,我正在用C语言创建一个多线程程序,我遇到了一些麻烦。 这里有创建线程的函数: void create_thread(t_game_data *game_data) { size_t i; t_args *args = malloc(sizeof(t_args)); i = 0; args->game = game_data; while (i < 10) { args->initialized = 0;
void create_thread(t_game_data *game_data)
{
size_t i;
t_args *args = malloc(sizeof(t_args));
i = 0;
args->game = game_data;
while (i < 10)
{
args->initialized = 0;
args->id = i;
printf("%zu CREATION\n", i);//TODO: Debug
pthread_create(&game_data->object[i]->thread_id, NULL, &do_action, args);
i++;
while (args->initialized == 0)
continue;
}
}
最后是处理创建的线程的函数
void *do_action(void *v_args)
{
t_args *args;
t_game_data *game;
size_t id;
args = v_args;
game = args->game;
id = args->id;
args->initialized = 1;
[...]
return (NULL);
}
问题是:
主线程创建新线程的速度将快于新线程初始化其变量的速度:
args = v_args;
game = args->game;
id = args->id;
因此,有时,两个不同的线程将从args->id
获得相同的id
。
为了解决这个问题,我使用变量initialized
作为bool,以便在新线程初始化期间使“sleep”成为主线程
但我认为这真的是有罪的。
也许有一种方法可以通过互斥来实现这一点?但我听说解锁一个不属于他的线程的互斥锁是不“合法”的
谢谢你的回答 > P>你应该考虑使用条件变量。你可以在这里找到一个例子。
基本上,在主线程中等待,在其他线程中发送信号。问题在于,在
create\u thread
中,您将相同的t\u args
结构传递给每个线程。实际上,您可能希望为每个线程创建自己的t_args结构
发生的事情是,您的第一个线程正在启动,并将args传递给它。在该线程可以运行do_action
之前,循环正在修改args结构。由于thread2和thread1都将指向相同的args结构,因此当它们运行do_action
时,它们将具有相同的id
哦,别忘了不要泄漏内存解决这个问题的最简单方法是向每个新线程传递一个不同的
t_args
对象。为此,将分配移动到循环中,并使每个线程负责释放自己的参数结构:
void create_thread(t_game_data *game_data) {
for (size_t i = 0; i < 10; i++) {
t_args *args = malloc(sizeof(t_args));
if (!args) {
/* ... handle allocation error ... */
} else {
args->game = game_data;
args->id = i;
printf("%zu CREATION\n", i);//TODO: Debug
if (pthread_create(&game_data->object[i]->thread_id, NULL,
&do_action, args) != 0) {
// thread creation failed
free(args);
// ...
}
}
}
}
// ...
void *do_action(void *v_args) {
t_args *args = v_args;
t_game_data *game = args->game;
size_t id = args->id;
free(v_args);
args = v_args = NULL;
// ...
return (NULL);
}
void创建线程(游戏数据*游戏数据){
对于(大小i=0;i<10;i++){
t_args*args=malloc(sizeof(t_args));
如果(!args){
/*…处理分配错误*/
}否则{
args->game=game\u数据;
args->id=i;
printf(“%zu创建\n”,i);//TODO:调试
如果(pthread\u create(&game\u data->object[i]->线程id,NULL,
&执行操作,参数)!=0){
//线程创建失败
免费(args);
// ...
}
}
}
}
// ...
void*do_动作(void*v_参数){
t_args*args=v_args;
t_game_data*game=args->game;
大小\u t id=args->id;
免费(v_args);
args=v_args=NULL;
// ...
返回(空);
}
但你也写:
为了解决这个问题,我使用了一个初始化为bool的变量,这样就可以“sleep”
新线程初始化期间的主线程
但我认为这真的是有罪的。也许有办法做到这一点
使用互斥锁?但是我听说解锁一个互斥锁是不合法的
不属于他的线
如果您仍然希望一个线程等待另一个线程修改某些数据,正如您最初的策略所要求的那样,那么您必须使用原子数据或某种类型的同步对象。否则,您的代码包含数据竞争,因此具有未定义的行为。实际上,您不能在原始代码中假设主线程将看到新线程写入args->initialized
。“有罪”是一种不寻常的描述方式,但如果你属于圣C教会,也许是合适的
使用互斥体可以解决这个问题,方法是只使用互斥体保护循环中的
args->initialized
测试,而不是整个循环,并使用相同的互斥体保护线程对该对象的写入,但这既讨厌又难看。最好是等待新线程增加信号量(不是繁忙的等待,并且初始化的
变量被信号量替换),或者设置并等待条件变量(同样不是繁忙的等待,但是仍然需要初始化的
变量或等效变量).除了几个主要问题外,你的解决方案在理论上应该是可行的
- 主线程将在while循环中旋转,该循环使用CPU周期检查标志(这是最不严重的问题,如果您知道它不需要等待很长时间,则可以正常工作)
- 对于空循环,编译器优化程序可以满足触发器的要求。他们也常常不知道一个变量可能会被其他线程修改,并在此基础上做出错误的决定李>
- 在多核系统上,主线程可能永远看不到对
的更改,或者如果更改位于另一个尚未刷新回主内存的内核的缓存中,则至少在很久以后才会看到更改args->initiialzed
#include <semaphore.h>
// other stuff
sem_t semaphore;
void create_thread(t_game_data *game_data)
{
size_t i;
t_args args;
i = 0;
if (sem_init(&semaphore, 0, 0) == -1) // third arg is initial value
{
// error
}
args.game = game_data;
while (i < 10)
{
args.id = i;
printf("%zu CREATION\n", i);//TODO: Debug
pthread_create(&game_data->object[i]->thread_id, NULL, &do_action, args);
sem_wait(&semaphore);
i++;
}
sem_destroy(&semaphore);
}
void *do_action(void *v_args) {
t_args *args = v_args;
t_game_data *game = args->game;
size_t id = args->id;
sem_post(&semaphore);
// Rest of the thread work
return NULL;
}
#包括
//其他东西
信号量;
无效创建线程(t_游戏数据*游戏数据)
{
尺寸i;
t_args args;
i=0;
if(sem_init(&信号量,0,0)==-1)//第三个参数是初始值
{
//错误
}
args.game=游戏数据;
而(i<10)
{
A.
#include <semaphore.h>
// other stuff
sem_t semaphore;
void create_thread(t_game_data *game_data)
{
size_t i;
t_args args;
i = 0;
if (sem_init(&semaphore, 0, 0) == -1) // third arg is initial value
{
// error
}
args.game = game_data;
while (i < 10)
{
args.id = i;
printf("%zu CREATION\n", i);//TODO: Debug
pthread_create(&game_data->object[i]->thread_id, NULL, &do_action, args);
sem_wait(&semaphore);
i++;
}
sem_destroy(&semaphore);
}
void *do_action(void *v_args) {
t_args *args = v_args;
t_game_data *game = args->game;
size_t id = args->id;
sem_post(&semaphore);
// Rest of the thread work
return NULL;
}