我的问题与C中的线程编程有关。
我的问题是我只想在我的main
程序中创建两个线程。这两个线程应该按顺序工作,这意味着我的第一个线程应该首先执行(不应该执行任何线程的其他语句)。第一个线程应该完全控制。在第一个线程完成之前,不应该执行任何其他线程的任何其他语句,甚至是main
程序语句。
第一个线程完成后,第二个线程应该以与第一个线程类似的方式执行。
之后我的主要应该执行。
我知道你可以说我为什么要这么做,因为这件事可以通过创建两个函数并按顺序调用它们来实现,但是对于学习和实验我想在线程的帮助下完成它。
我在C中编写了一些代码,如下所示:
void* fun()
{
printf("\nThe thread 1 is running");
}
void* van()
{
printf("\nthread 2 is running ");
}
int main()
{
pthread_t t1,t2;
pthread_create(&t1,NULL,fun,NULL);
pthread_create(&t2,NULL,van,NULL);
printf("\nI'm in main\n");
pthread_join(t2,NULL);
}
该程序运行良好,但我不理解函数pthread_join()
的工作原理。
当我稍微更改我的代码时如下:
int main()
{
pthread_t t1,t2;
pthread_create(&t1,NULL,fun,NULL);
pthread_join(t2,NULL); // Change
pthread_create(&t2,NULL,van,NULL);
printf("\nI'm in main\n");
}
现在,当我运行代码时,它会显示分段错误。
现在我的问题如下:
pthread_create()
函数中的属性参数是什么?我们为什么要使用它们?线程的默认属性是什么?请举例说明。pthread_create()
函数中的参数是什么?为什么我们使用它们?线程的默认参数是什么?请举例说明。pthread_join()
如何实际运作?当我的代码在main pthread_join()
中调用t2
作为第一个参数时,这意味着什么。这是否意味着主要应该暂停执行直到t2执行完成或其他什么? pthread_join()
中的第二个参数是什么?我们为什么用它?它的默认值是多少?请用示例或代码进行解释。答案 0 :(得分:7)
attr参数指向pthread_attr_t结构,其内容在创建线程时用于确定新线程的属性;使用pthread_attr_init(3)和相关函数初始化此结构。如果attr为NULL,则使用默认属性(source)创建线程。
参数传递给您的线程函数。这是将数据传递给线程的最佳方式(与使用全局变量相反,例如)。
是的,pthread_join
等待线程完成。这就是你在启动线程之前调用pthread_join
时程序失败的原因,因为t2在那时包含了垃圾。
如果retval不为NULL,则pthread_join()将目标线程的退出状态(即目标线程提供给pthread_exit(3)的值)复制到* retval指向的位置。如果目标线程被取消,则PTHREAD_CANCELED被置于* retval中。 (source)。
即,你可以让你的线程函数通知你它的执行结果。
鉴于此,您的线程创建可能如下所示:
struct th_arg{
...
};
static void th_work(struct th_arg* a){
//...some work
if (success) pthread_exit(EXIT_SUCCESS)
else pthread_exit(ERROR_CODE);
}
int main(){
int t1,t2;
struct th_arg[2];
int codes[2];
// initialize th_arg2
pthread_create(&t1, NULL, th_work, th_arg+0, th_arg+0);
pthread_create(&t2, NULL, th_work, th_arg+1, th_arg+1);
pthread_join(t1, codes+0);
pthread_join(t2, codes+1);
if (codes[0] == EXIT_SUCCESS && codes[1] == EXIT_SUCCESS){
...
}
}
答案 1 :(得分:2)
学习posix线程的最佳来源是https://computing.llnl.gov/tutorials/pthreads/
答案 2 :(得分:1)
pthread_create
中的属性属于pthread_attr_t
类型。它包含有关线程的信息,包括线程的内存地址开始的位置以及堆栈的大小。大多数情况下,您不需要使用此参数。
pthread_create
中的arg作为唯一参数传递给start_routine
函数。这是一种黑客行为。因为指针可以指向任何东西(int,数组,结构等),所以你可以通过传递一个指向你要传入的所有数据的指针来传入你的参数。大多数时候,人们最终会进入结构。线程没有默认参数。如果您不想传递任何内容,只需将arg
指定为NULL。
举个例子:
struct arguments
{
int something;
char* anotherArg;
short stillAnotherArg;
}
void* fun(void* arg)
{
struct arguments *my_args = (struct arguments*)arg;
printf("You said: %s\n", my_args->anotherArg); // Will print "You said: Hello there"
...
}
int main()
{
pthread_t t1;
struct arguments my_args;
my_args.something = 5;
my_args.anotherArg = "Hello there";
my_args.stillAnotherArg = 42;
pthread_create (&t1,NULL,fun, &my_args);
...
}
pthread_join
阻止调用者,直到指定的线程完成。
pthread_join
的第二个参数允许您在完成执行后捕获线程的返回值。每个线程都返回void*
,第二个参数允许您指定存储返回值的位置。
举个例子:
void* fun(void* arg)
{
...
return NULL; // not very exciting, but I don't want to get
// into memory management problems right now
}
int main()
{
...
void* theReturnValue;
pthread_join(t2, &theReturnValue);
printf("fun returned %p\n", theReturnValue); // will print "fun returned 0x0"
// which is NULL
}
最后,它出现segfaults的原因是因为你正在等待一个尚未定义的线程。
答案 3 :(得分:0)
您可以通过包含 omp.h 来使用 omp 库。它很容易使用。 您可以使用指令
创建并行部分#pragma omp parallel
{
// PARALLEL Code
}
使用omp_set_num_threads(2);
设置主题号码,然后使用omp_get_thread_num();
示例:
omp_set_num_threads(2);
#pragma omp parallel
{
printf("thread %d said hello", omp_get_thread_num());
}