如何使用pthread_create创建并发线程?

作者:浙江麻将开发公司 阅读:47 次 发布时间:2025-05-05 16:45:55

摘要:在多线程编程中,创建并发线程是非常重要的一项技能。pthread_create是Unix/Linux系统下常用的函数,它允许我们创建新的线程。本文将介绍如何使用pthread_create函数创建并发线程。一、pthread_create函数概述在开始介绍pthread_create函数之前,我们需要了解一下线程的概念。...

在多线程编程中,创建并发线程是非常重要的一项技能。pthread_create是Unix/Linux系统下常用的函数,它允许我们创建新的线程。本文将介绍如何使用pthread_create函数创建并发线程。

如何使用pthread_create创建并发线程?

一、pthread_create函数概述

在开始介绍pthread_create函数之前,我们需要了解一下线程的概念。线程是操作系统调度的基本单位,每个线程具有自己独立的执行流和栈空间。线程可以共享进程内的数据和代码,但拥有自己的寄存器和栈。

pthread_create函数用于创建新的线程。其函数原型如下:

```

#include

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

void *(*start_routine)(void*), void *arg);

```

pthread_create函数的四个参数分别是:

1. pthread_t *thread:指向新线程的ID。当pthread_create成功创建一个新线程时,线程ID将被返回,并可以被用于其他pthread库函数中。

2. const pthread_attr_t *attr:线程的属性。可以使用该参数来指定线程的属性,如线程的调度策略、优先级、堆栈大小和是否分离等。

3. void *(*start_routine)(void*):新线程将执行的函数的地址。该函数应该以void*类型的指针作为参数,并返回void*类型的指针。start_routine函数的参数将传递给新线程。

4. void *arg:start_routine的参数。可以使用该参数传递给start_routine函数的参数。

pthread_create函数执行成功时,返回0;否则,它返回一个非零错误代码。下面是一个简单的示例:

```

#include

void* hello_world(void* arg)

{

printf("Hello, world!\n");

return NULL;

}

int main()

{

pthread_t thread_id;

pthread_create(&thread_id, NULL, hello_world, NULL);

pthread_join(thread_id, NULL);

return 0;

}

```

在上面的代码中,我们定义了一个名为hello_world的函数,它将作为新线程的入口点。我们使用pthread_create函数创建了一个新线程,并将其ID保存在thread_id变量中。在main函数中,我们使用pthread_join函数来等待新线程结束。这可以确保主线程在新线程完成之前不会退出。pthread_join函数的参数是指向要等待的线程ID的指针和一个指向线程返回值的指针(我们在此示例中忽略了线程返回值)。

虽然上面的代码很简单,但它演示了pthread_create函数的基本用法。接下来,我们将更详细地介绍pthread_create函数。

二、线程属性

在使用pthread_create函数之前,我们需要了解线程属性。线程属性用于描述线程的各种特性。pthread库使用pthread_attr_t数据类型来表示线程属性。可以使用pthread_attr_init函数来初始化线程属性。如果不需要特殊的线程属性,可以使用NULL作为pthread_create函数的第二个参数。

以下代码用于演示如何初始化线程属性并将其传递给pthread_create函数:

```

#include

#include

void* hello_world(void* arg)

{

printf("Hello, world!\n");

return NULL;

}

int main()

{

pthread_t thread_id;

pthread_attr_t attr;

pthread_attr_init(&attr);

pthread_create(&thread_id, &attr, hello_world, NULL);

pthread_join(thread_id, NULL);

return 0;

}

```

在上面的代码中,我们定义了一个名为attr的pthread_attr_t变量,并使用pthread_attr_init函数将其初始化。我们使用&attr参数将线程属性传递给pthread_create函数。

我们可以通过调用pthread_attr_setdetachstate函数将线程属性设置为分离线程或非分离线程。默认情况下,线程是非分离的。当一个非分离线程终止时,它的资源被保留,直到调用pthread_join函数等待该线程终止。与之相反,当一个分离线程终止时,它的资源将立即被释放,无法通过pthread_join函数等待该线程终止。

以下代码演示了如何将线程属性设置为分离线程:

```

#include

#include

void* hello_world(void* arg)

{

printf("Hello, world!\n");

return NULL;

}

int main()

{

pthread_t thread_id;

pthread_attr_t attr;

pthread_attr_init(&attr);

pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

pthread_create(&thread_id, &attr, hello_world, NULL);

// 不再调用pthread_join

return 0;

}

```

这里我们使用了PTHREAD_CREATE_DETACHED常量,将线程设置为分离线程。请注意,当线程属性设置为分离线程时,我们不再需要调用pthread_join函数等待线程终止。

三、线程创建及结束

如果新线程成功创建,pthread_create函数将返回0。线程可以自行结束,也可以被其他线程取消。在我们的例子中,我们使用了pthread_join函数来等待新线程结束。如果我们不调用pthread_join函数,可能会导致新线程成为孤儿线程。孤儿线程将成为操作系统管理的资源,直到它完成执行或被取消。

以下代码演示了如何使用pthread_join函数等待新线程结束:

```

#include

#include

void* hello_world(void* arg)

{

printf("Hello, world!\n");

return NULL;

}

int main()

{

pthread_t thread_id;

pthread_create(&thread_id, NULL, hello_world, NULL);

pthread_join(thread_id, NULL);

return 0;

}

```

在上面的代码中,我们创建了一个新线程,并使用pthread_join函数等待其完成执行。但是,如果新线程非常耗时,可能会阻塞主线程的执行,我们可以考虑使用线程取消功能。

使用pthread_cancel函数可以在一个线程中取消另一个线程。被取消的线程将立即停止执行,并进入取消状态。被取消的线程可以在任何时候调用pthread_exit函数主动结束,或等待操作系统管理。

以下代码演示了如何调用pthread_cancel函数来取消另一个线程:

```

#include

#include

#include

void* long_running(void* arg)

{

while (1)

{

printf("Working...\n");

sleep(1);

}

return NULL;

}

int main()

{

pthread_t thread_id;

pthread_create(&thread_id, NULL, long_running, NULL);

sleep(5);

pthread_cancel(thread_id);

pthread_join(thread_id, NULL);

return 0;

}

```

在上面的代码中,我们定义了一个名为long_running的函数,它将成为新线程的入口点。我们使用pthread_create函数创建了一个新线程,并将其ID保存在变量thread_id中。我们使用sleep函数暂停主线程的执行,让新线程执行一段时间。最后,我们调用pthread_cancel来取消新线程。请注意,当线程被取消后,我们需要调用pthread_join函数等待它被完全取消。

四、线程同步

在多线程编程中,由于多个线程可能访问同一个共享资源,因此需要进行线程同步。如果两个或多个线程同时修改同一个共享变量,可能会导致数据不一致或者数据丢失。

在Unix和Linux系统下,pthread库提供了多种同步机制,比如互斥锁、条件变量、信号量等。互斥锁是pthread库中最简单的同步机制。当一个线程取得互斥锁时,其他线程必须等待该线程释放互斥锁后才能继续执行。

以下代码演示了如何使用pthread库中的互斥锁来保护共享资源:

```

#include

#include

#include

pthread_mutex_t mutex;

int shared_data = 0;

void* add_thread(void* arg)

{

pthread_mutex_lock(&mutex);

shared_data++;

printf("Add thread: shared_data = %d\n", shared_data);

pthread_mutex_unlock(&mutex);

return NULL;

}

void* sub_thread(void* arg)

{

pthread_mutex_lock(&mutex);

shared_data--;

printf("Sub thread: shared_data = %d\n", shared_data);

pthread_mutex_unlock(&mutex);

return NULL;

}

int main()

{

pthread_t t1, t2, t3;

pthread_mutex_init(&mutex, NULL);

pthread_create(&t1, NULL, add_thread, NULL);

pthread_create(&t2, NULL, sub_thread, NULL);

pthread_create(&t3, NULL, sub_thread, NULL);

pthread_join(t1, NULL);

pthread_join(t2, NULL);

pthread_join(t3, NULL);

pthread_mutex_destroy(&mutex);

return 0;

}

```

在上面的代码中,我们定义了一个名为shared_data的全局变量,并且在add_thread函数和sub_thread函数中使用了互斥锁来保护它。当一个线程取得互斥锁时,其他线程必须等待该线程把互斥锁释放后才能进入临界区。在这个例子中,我们创建了三个线程来修改共享变量shared_data。请注意,这个例子只是一个简单的演示,实际上在生产环境中我们可能会需要更复杂的同步机制。

五、总结

在本文中,我们介绍了如何使用pthread_create函数创建并发线程。我们学习了如何使用线程属性来控制线程的特性,如何等待新线程结束,如何取消一个线程,以及如何使用互斥锁来保护共享资源。

在使用多线程编程时,我们需要注意线程安全问题,以避免由于多个线程访问同一个共享变量而导致的意外情况。使用pthread库提供的同步机制,可以保证线程的安全性。

希望本文对读者们有所帮助,使大家能够更加熟练地使用pthread_create函数创建并发线程。

  • 原标题:如何使用pthread_create创建并发线程?

  • 本文链接:https://qipaikaifa.cn/zxzx/15049.html

  • 本文由深圳中天华智网小编,整理排版发布,转载请注明出处。部分文章图片来源于网络,如有侵权,请与中天华智网联系删除。
  • 微信二维码

    ZTHZ2028

    长按复制微信号,添加好友

    微信联系

    在线咨询

    点击这里给我发消息QQ客服专员


    点击这里给我发消息电话客服专员


    在线咨询

    免费通话


    24h咨询☎️:157-1842-0347


    🔺🔺 棋牌游戏开发24H咨询电话 🔺🔺

    免费通话
    返回顶部