C语言多线程操作

C语言多线程操作C 语言多线程操作目录 C 语言多线程 创建线程 终止线程 注意 信号量机制 参考博文 返回目录 C 语言多线程多线程是多任务处理的一种特殊形式 多任务处理允许让电脑同时运行两个或两个以上的程序 一般情况下 两种类型的多任务处理 基于进程和基于线程 基于进程的多任务处理是程序的并发执行 基于线程的多任务处理是同一程序的片段的并发执行 多线程程序包含可以同时运行

C语言多线程操作

目录

  • C语言多线程
  • 创建线程
  • 终止线程
  • 注意
  • 信号量机制
  • 参考博文:

 


返回目录

C语言多线程

多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下,两种类型的多任务处理:基于进程和基于线程

  • 基于进程的多任务处理是程序的并发执行。
  • 基于线程的多任务处理是同一程序的片段的并发执行。

多线程程序包含可以同时运行的两个或多个部分。这样的程序中的每个部分称为一个线程,每个线程定义了一个单独的执行路径。

本教程假设您使用的是 Linux 操作系统,我们要使用 POSIX 编写多线程 C++ 程序。POSIX Threads 或 Pthreads 提供的 API 可在多种类 Unix POSIX 系统上可用,比如 FreeBSD、NetBSD、GNU/Linux、Mac OS X 和 Solaris。

返回目录

创建线程

下面的程序,我们可以用它来创建一个POSIX 线程:

#include 
   
     pthread_create (thread, attr, start_routine, arg) 
   

在这里,pthread_create 创建一个新的线程,并让它可执行。下面是关于参数的说明:

C语言多线程操作

目录

  • C语言多线程
  • 创建线程
  • 终止线程
  • 注意
  • 信号量机制
  • 参考博文:

 


返回目录

C语言多线程

多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下,两种类型的多任务处理:基于进程和基于线程

  • 基于进程的多任务处理是程序的并发执行。
  • 基于线程的多任务处理是同一程序的片段的并发执行。

多线程程序包含可以同时运行的两个或多个部分。这样的程序中的每个部分称为一个线程,每个线程定义了一个单独的执行路径。

本教程假设您使用的是 Linux 操作系统,我们要使用 POSIX 编写多线程 C++ 程序。POSIX Threads 或 Pthreads 提供的 API 可在多种类 Unix POSIX 系统上可用,比如 FreeBSD、NetBSD、GNU/Linux、Mac OS X 和 Solaris。

返回目录

创建线程

下面的程序,我们可以用它来创建一个POSIX 线程:

#include 
       
         pthread_create (thread, attr, start_routine, arg) 
       

在这里,pthread_create 创建一个新的线程,并让它可执行。下面是关于参数的说明:

参数 描述
thread 指向线程标识符指针。
attr 一个不透明的属性对象,可以被用来设置线程属性。您可以指定线程属性对象,也可以使用默认值 NULL。
start_routine 线程运行函数起始地址,一旦线程被创建就会执行。
arg 运行函数的参数。它必须通过把引用作为指针强制转换为 void 类型进行传递。如果没有传递参数,则使用 NULL。

创建线程成功时,函数返回 0,若返回值不为 0 则说明创建线程失败。

返回目录

终止线程

使用下面的程序,我们可以用它来终止一个 POSIX 线程:

#include 
       
         pthread_exit (status) 
       

在这里,pthread_exit 用于显式地退出一个线程。通常情况下,pthread_exit() 函数是在线程完成工作后无需继续存在时被调用。

如果 main() 是在它所创建的线程之前结束,并通过 pthread_exit() 退出,那么其他线程将继续执行。否则,它们将在 main() 结束时自动被终止。

连接和分离线程

我们可以使用以下两个函数来连接或分离线程:

pthread_join (threadid, status) pthread_detach (threadid)

pthread_join() 子程序阻碍调用程序,直到指定的 threadid 线程终止为止。当创建一个线程时,它的某个属性会定义它是否是可连接的(joinable)或可分离的(detached)。只有创建时定义为可连接的线程才可以被连接。如果线程创建时被定义为可分离的,则它永远也不能被连。pthread_join() 函数来等待线程的完成。

返回目录

注意

pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a, 在使用pthread_create创建线程时,在编译中要加-lpthread参数:

 

 gcc createThread.c -lpthread -o createThread.o ./createThread.

Test 1 无参数传递的线程并发编程实例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

// 基于线程的并发编程

// Test_1 createThread

#include

#include

/*

 * pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a,

 * 在使用pthread_create创建线程时,在编译中要加-lpthread参数:

 * gcc createThread.c -lpthread -o createThread.o

 * ./createThread.o

 * 加上上面两句以后编译成功,并输出结果

 * */

#define NUM_Threads 5

 

// 线程的运行函数

void *PrintHello(void *arg)

{

    printf("Hello,World of Thread in C!\n");

    return 0;

}

 

int main()

{

    int i;

    int ret;

    // 定义线程的id变量,多个变量使用数组

    pthread_t tids[NUM_Threads];

 

    for (i=0; i

    {

        // 参数依次是: 创建的线程id,线程参数,调用的函数,传入的函数参数

       ret = pthread_create(&tids[i], NULL, PrintHello, NULL);

       if (ret != 0)

      {

          printf("pthread_create error: error_code = \n");

      }

    }

    // 等各个线程推出后,进程才结束

    pthread_exit(NULL);

 

    return 0;

}

 

/*

 * 在CLion(Ubuntu)中输出结果为

Hello,World of Thread in C!

Hello,World of Thread in C!

Hello,World of Thread in C!

Hello,World of Thread in C!

Hello,World of Thread in C!

 * */

Test 2 简单参数传递的线程并发编程实例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

// 基于线程的并发编程,向线程传递参数1

// Test_2_createThread

#include

#include

#include

#define NUM_Threads 5

 

// 线程的运行函数

void *PrintHelloId(void *threadid)

{

    // 对传入的参数进行强制类型转换,由无类型指针变为整形指针,然后再读取

    int tid = *((int *)threadid);

    printf("Hello,World, Thread %d\n",tid);

    return 0;

}

 

int main()

{

    pthread_t pthreads[NUM_Threads];

    int i, rc;

    // 用数组存储i的数值

    int indexes[NUM_Threads];

 

    for (i=0; i

    {

        printf("main() : 创建线程 %d \n",i);

        indexes[i] = i; // 保存i的数值

        // 在indexes传入参数的时候必须转换为无类型指针

        rc = pthread_create(&pthreads[i], NULL, PrintHelloId, (void *)&indexes[i]);

        if (0 != rc)

        {

            printf("Error: 无法创建线程!\n");

            exit(-1);

        }

    }

 

    pthread_exit(NULL);

    return 0;

}

 

/*

 * 在CLion(Ubuntu)中输出结果是

main() : 创建线程 0

main() : 创建线程 1

Hello,World, Thread 0

main() : 创建线程 2

Hello,World, Thread 1

main() : 创建线程 3

Hello,World, Thread 2

main() : 创建线程 4

Hello,World, Thread 3

Hello,World, Thread 4

 * */

Test 3 结构体参数传递的线程并发编程实例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

// 基于线程的并发编程,向线程传递参数2(传递结构体)

// Test_3_createThread

#include

#include

#include

#define NUM_Threads 5

 

typedef struct thread_data{

    int threadid;

    char message;

}THDATA,*PTHDATA;

 

void * PrintHello(void * pthreadid)

{

    PTHDATA tid = (PTHDATA)pthreadid;

 

    printf("This is Pthread : %d ;info : %c \n",tid->threadid, tid->message);

 

    return 0;

}

 

int main(void)

{

    pthread_t Pthread[NUM_Threads];

    THDATA index[NUM_Threads];

    int i, ret;

 

    for (i = 0; i < NUM_Threads; i++)

    {

        printf("main() : 创建线程 %d \n",i);

        index[i].threadid = i;

        index[i].message = 'A'+i%10;

        ret = pthread_create(&Pthread[i], NULL, PrintHello, (void *)&index[i]);

        if (0 != ret)

        {

            printf("Error: 创建线程失败!\n");

            exit(-1);

        }

    }

    pthread_exit(NULL);

    return 0;

}

 

/*

 * 在CLion(Ubuntu)中输出结果是

main() : 创建线程 0

main() : 创建线程 1

This is Pthread : 0 ;info : A

main() : 创建线程 2

main() : 创建线程 3

This is Pthread : 2 ;info : C

main() : 创建线程 4

This is Pthread : 3 ;info : D

This is Pthread : 4 ;info : E

This is Pthread : 1 ;info : B

 * */

Test 4 线程的连接编程实例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

// 基于线程的并发编程,连接或分离线程

// Test_4_createThread

// 2019年10月27日14:45:11 尚未完全搞明白

#include

#include

#include

 

#define NUM_Pthread 5

 

void *PrintHello(void * pthreadid)

{

    int tid = *((int *)pthreadid);

    printf("Sleeping in thread %d ,...exiting \n",tid);

    return 0;

}

 

int main(void)

{

    int i, ret;

    pthread_t Pthread[NUM_Pthread];

    pthread_attr_t attr; // 定义线程属性

    void * status;

    int index[NUM_Pthread];

 

    // 初始化并设置线程为可连接

    pthread_attr_init(&attr);

    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

 

    for (i=0; i

    {

        printf("main() : 创建线程 %d \n",i);

        index[i] = i;

        ret = pthread_create(&Pthread[i], NULL, PrintHello, (void *)&index[i]);

    }

 

    // 删除属性,并等待其他线程

    pthread_attr_destroy(&attr);

    for (i=0; i

    {

        ret = pthread_join(Pthread[i], status);

        if (0 != ret)

        {

            printf("Error: unable to join,%d\n",ret);

            exit(-1);

        }

        printf("main(): complete thread id : %d",i);

        printf(" exiting with status : %p\n",status);

    }

 

    printf("main() : program exiting.\n");

    pthread_exit(NULL);

 

    return 0;

}

返回目录

信号量机制

Test 5 信号量同步进行写入

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

// 用信号量进行同步

#include

#include

#include

#include

#include

#include

 

#define Len 100       // 设置输入内容长度

 

sem_t bin_sem;

char work_area[Len]; // 存放输入内容

 

void *Thread_func(void *arg)

{

    // 等待信号量有大于0的值然后退出

    sem_wait(&bin_sem);

    while (0 != strncmp("end", work_area, 3))

    {

        printf("Input %ld characters\n", strlen(work_area)-1);

    }

    return 0;

}

 

int main(void)

{

    int res;    // 存放命令的返回值

    pthread_t Pthread; // 创建线程

    void *thread_result; // 存放线程处理结果

 

    // 初始化信号量,并设置初始值为0

    res = sem_init(&bin_sem, 0, 0);

    if (0 != res)

    {

        perror("Semaphore initialization failes");

        exit(EXIT_FAILURE);

    }

    // 创建新线程 0

    res = pthread_create(&Pthread, NULL, Thread_func, NULL);

    if (0 != res)

    {

        perror("Thread creation failed");

        exit(EXIT_FAILURE);

    }

    printf("Enter 'end' to finish\n");

    // 当工作区内不是以end开头的字符串,则继续输入

    while (0 != strncmp("end", work_area, 3))

    {

        // 以标准输入获取输入到工作区内

        fgets(work_area, Len, stdin);

        sem_post(&bin_sem);  // 信号量+1

    }

    printf("\n Waiting for thread to finish...\n");

    // 等待线程结束

    res = pthread_join(Pthread, &thread_result);

    if (0 != res)

    {

        perror("Thread join failed");

        exit(EXIT_FAILURE);

    }

    printf("Thread joined\n");

    sem_destroy(&bin_sem);  // 销毁信号量

    exit(EXIT_SUCCESS);

 

    return 0;

}

Test 6 互斥信号量实现对临界资源操作

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

// 用互斥信号量进行同步

#include

#include

#include

#include

 

#define Len 3 // 自增计算次数

#define NUM_Pthread 5 // 设置线程的长度

 

int count = 1; // 在数据段共享资源,多个进程抢占临界资源

// 对于临界资源,应该添加互斥锁

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

 

void *Thread_func(void *threadid)

{

    int tid = *((int *)threadid);

    int i, val;

    printf("Pthread ID : %d \n",tid);

 

    for (i=0; i

    {

        pthread_mutex_lock(&mutex);

        val = count;

        printf("val = %d \n",val++);

        count = val;

        pthread_mutex_unlock(&mutex);

    }

 

    return 0;

}

 

int main(void)

{

    int res;    // 存放命令的返回值

    int i;

    pthread_t Pthread[NUM_Pthread]; // 创建线程

    int index[NUM_Pthread];

 

    for (i=0; i

    {

        index[i] = i;

        // 创建线程

       res = pthread_create(&Pthread[i], NULL, Thread_func, (void *)&index[i]);

       if (0 != res)

       {

           printf("Error: 创建线程失败!\n");

           exit(-1);

       }

    }

 

    for (i=0; i

    {

        // 汇合线程

        pthread_join(Pthread[i], NULL);

    }

    printf("count = %d\n",count);

    pthread_exit(NULL);

    return 0;

}

 

// 在运行此程序无互斥锁时,我们不仅得到错误的答案,而且每次得到的答案都不相同

// 分析

// 当多个对等线程在一个处理器上并发运行时,机器指令以某种顺序完成,每个并发执行定义了线程中指令的某种顺序

 
   
   
   
   

创建线程成功时,函数返回 0,若返回值不为 0 则说明创建线程失败。

返回目录

终止线程

使用下面的程序,我们可以用它来终止一个 POSIX 线程:

#include 
   
     pthread_exit (status) 
   

在这里,pthread_exit 用于显式地退出一个线程。通常情况下,pthread_exit() 函数是在线程完成工作后无需继续存在时被调用。

如果 main() 是在它所创建的线程之前结束,并通过 pthread_exit() 退出,那么其他线程将继续执行。否则,它们将在 main() 结束时自动被终止。

连接和分离线程

我们可以使用以下两个函数来连接或分离线程:

pthread_join (threadid, status) pthread_detach (threadid)

pthread_join() 子程序阻碍调用程序,直到指定的 threadid 线程终止为止。当创建一个线程时,它的某个属性会定义它是否是可连接的(joinable)或可分离的(detached)。只有创建时定义为可连接的线程才可以被连接。如果线程创建时被定义为可分离的,则它永远也不能被连。pthread_join() 函数来等待线程的完成。

返回目录

注意

pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a, 在使用pthread_create创建线程时,在编译中要加-lpthread参数:

 

 gcc createThread.c -lpthread -o createThread.o ./createThread.

Test 1 无参数传递的线程并发编程实例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

// 基于线程的并发编程

// Test_1 createThread

#include

#include

/*

 * pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a,

 * 在使用pthread_create创建线程时,在编译中要加-lpthread参数:

 * gcc createThread.c -lpthread -o createThread.o

 * ./createThread.o

 * 加上上面两句以后编译成功,并输出结果

 * */

#define NUM_Threads 5

 

// 线程的运行函数

void *PrintHello(void *arg)

{

    printf("Hello,World of Thread in C!\n");

    return 0;

}

 

int main()

{

    int i;

    int ret;

    // 定义线程的id变量,多个变量使用数组

    pthread_t tids[NUM_Threads];

 

    for (i=0; i

    {

        // 参数依次是: 创建的线程id,线程参数,调用的函数,传入的函数参数

       ret = pthread_create(&tids[i], NULL, PrintHello, NULL);

       if (ret != 0)

      {

          printf("pthread_create error: error_code = \n");

      }

    }

    // 等各个线程推出后,进程才结束

    pthread_exit(NULL);

 

    return 0;

}

 

/*

 * 在CLion(Ubuntu)中输出结果为

Hello,World of Thread in C!

Hello,World of Thread in C!

Hello,World of Thread in C!

Hello,World of Thread in C!

Hello,World of Thread in C!

 * */

Test 2 简单参数传递的线程并发编程实例

+ View Code

Test 3 结构体参数传递的线程并发编程实例

+ View Code

Test 4 线程的连接编程实例

+ View Code

返回目录

信号量机制

Test 5 信号量同步进行写入

+ View Code

Test 6 互斥信号量实现对临界资源操作

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

// 用互斥信号量进行同步

#include

#include

#include

#include

 

#define Len 3 // 自增计算次数

#define NUM_Pthread 5 // 设置线程的长度

 

int count = 1; // 在数据段共享资源,多个进程抢占临界资源

// 对于临界资源,应该添加互斥锁

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

 

void *Thread_func(void *threadid)

{

    int tid = *((int *)threadid);

    int i, val;

    printf("Pthread ID : %d \n",tid);

 

    for (i=0; i

    {

        pthread_mutex_lock(&mutex);

        val = count;

        printf("val = %d \n",val++);

        count = val;

        pthread_mutex_unlock(&mutex);

    }

 

    return 0;

}

 

int main(void)

{

    int res;    // 存放命令的返回值

    int i;

    pthread_t Pthread[NUM_Pthread]; // 创建线程

    int index[NUM_Pthread];

 

    for (i=0; i

    {

        index[i] = i;

        // 创建线程

       res = pthread_create(&Pthread[i], NULL, Thread_func, (void *)&index[i]);

       if (0 != res)

       {

           printf("Error: 创建线程失败!\n");

           exit(-1);

       }

    }

 

    for (i=0; i

    {

        // 汇合线程

        pthread_join(Pthread[i], NULL);

    }

    printf("count = %d\n",count);

    pthread_exit(NULL);

    return 0;

}

 

// 在运行此程序无互斥锁时,我们不仅得到错误的答案,而且每次得到的答案都不相同

// 分析

// 当多个对等线程在一个处理器上并发运行时,机器指令以某种顺序完成,每个并发执行定义了线程中指令的某种顺序

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/176971.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午8:36
下一篇 2026年3月26日 下午8:36


相关推荐

  • ebpf技术_EBM技术

    ebpf技术_EBM技术1.ebpf概述1.1ebpf发展历史BPF,及伯克利包过滤器BerkeleyPacketFilter,最初构想提出于1992年,其目的是为了提供一种过滤包的方法,并且要避免从内核空间到用户空间的无用的数据包复制行为。它最初是由从用户空间注入到内核的一个简单的字节码构成,它在那个位置利用一个校验器进行检查——以避免内核崩溃或者安全问题——并附着到一个套接字上,接着在每个接…

    2026年2月11日
    4
  • PHP采集程序原理分析篇

    PHP采集程序原理分析篇由于需要 要写一个简单的 PHP 采集程序 照例是到网上找了一堆教程 然后照猫画虎 可是发现网上的教程全是似是而非 没有一个真正能用的 苦想了几天 终于弄明白了里面的道理 在这里写出来 请高手指正 采集程序的思路很简单 无非就是先打一个页面 一般都是列表页 取得里面全部链接的地址 然后打开逐条链接 寻找我们感兴趣的东西 如果找到 就把它入库或别的处理 下面以一个很简单的例子来说说 首先确定一个

    2026年3月17日
    2
  • 什么品种的猫最受欢迎?Python爬取猫咪网站交易数据[通俗易懂]

    什么品种的猫最受欢迎?Python爬取猫咪网站交易数据[通俗易懂]本篇文章是关于某化妆品企业的销售分析。从分析思路开始带大家一步步地用python进行分析,找出问题,并提出解决方案的整个流程。以下文章来源于修炼Python作者:叶庭云Python爬虫、数据分析、网站开发等案例教程视频免费在线观看https://space.bilibili.com/523606542一、前言看到可爱的猫咪表情包,总是会忍不住收藏,晒部分图如下:认识的一些朋友也养了猫,比如橘猫、英短、加菲猫之类的,看他们发朋友圈撸猫,老羡慕了,猫咪真的太可爱啦。发.

    2025年11月14日
    2
  • 如何用burpsuite抓包[通俗易懂]

    如何用burpsuite抓包[通俗易懂]首先:使用火狐浏览器,并下载插件proxy点击上图右边的按钮并选择附加组件查询并下载插件配置代理点击options,然后add需要抓包时点击绿色的就行了burpsuite首先我们来到proxy界面在开启插件代理和interceptison的情况下点击某个链接即可抓取数据包需要改包发包的话可以直接在这里修改后直接forward或者同时按ctrl和r在下图…

    2022年5月20日
    70
  • 码云,git使用 教程

    码云,git使用 教程codecloud, git usetutorials作者:韩梦飞沙Author:han_meng_fei_sha 邮箱:313134555@qq.comE-mail:313134555@qq.com  新建项目newproject  路径

    2022年4月9日
    46
  • XPS文件转换为PDF不再愁!全新XPS/EPS文档处理神器Aspose.Page来啦!

    XPS文件转换为PDF不再愁!全新XPS/EPS文档处理神器Aspose.Page来啦!近月,针对Aspose.XPS和Aspose.EPS做了一些改动,将其合并成Aspose.Page,同样可以使用现有许可证访问这两种产品的所有功能。Aspose.Page(点击下载)是集成On-PremiseAPI,以.NET和Java应用程序中创建,操作或转换XPS,EPS和PS文件。或使用免费应用程序即时查看或转换文件。功能亮点Aspose.Page允许文档转换。例如,您可以将XPS…

    2022年5月4日
    80

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号