【C语言】多线程

多线程进行协同运算

创建一个数组,其中有5000个元素,我们想用两个线程来共同计算这5000个元素的加法和。

int arr[5000];
int s1 = 0;
int s2 = 0;
void *func1(void *args){
	int i;
	char *name = (char *)args;
	for(i = 1; i < 2500; i++){
		s1 += arr[i];
	}
		return NULL;
}
void *func1(void *args){
	int i;
	char *name = (char *)args;
	for(i = 2500; i < 5000; i++){
		s2 += arr[i];
	}
		return NULL;
}

从两个线程的函数可以看出,一个线程计算前2500个值的加法和,另一个线程计算后2500个值的加法和。

int main(){
	int i;
	for(i = 0; i <5000; i++){
		arr[i]  =  rand() % 50;
	}
	pthread_ th1;
	pthread_t th2;
	pthread_create(&th1, NULL, func1,  NULL);
	pthread_create(&th2, NULL, func2, NULL);
	pthread_join(th1, NULL);
	pthread_join(th2, NULL);
	printf("s1 = %d, s2 = %d, s1+s2 = %d\n", s1, s2, s1+s2);
	return 0;
}

main函数中,在pthread_join函数等待的th1th2都结束后,输出对应的值。

代码里,th1和th2的执行函数中有大量的相似代码,所以我们最后用一个函数来复用。不难想到,需要通过传参的方式来实现代码复用。这里我们定义一个结构体,结构体中有循环的起始标记first,终止标记last,区间内加法和result。

typedef struct{
	int first;
	int last;
	int result;
}MY_ARGS;
int arr[5000];
void *func(void *args){
	int i;
	int s = 0;
	//参数强制类型转换
	MY_ARGS *my_args = (MY_ARGS *)args;
	for(i = my_args->first; i < my_args->last; i++){
		s += arr[i];
	}
	my_args->result = s;
	return NULL;
}

func1fun2整合到了func中去。而在main函数中,我们创建线程的时候传入的参数正是结构体指针:

int main(){
	int i;
	for(i = 0; i < 5000; i++){
		arr[i] = rand() % 50;
	}
	pthread_t th1;
	pthread_t th2;
	MY_ARGS args1 = {0, 2500, 0};
	MY_ARGS args2 =  {2500, 5000, 0};
	pthread_create(&th1, NULL, func, &args1);
	pthread_create(&th2, NULL, func, &args2);
	pthread_join(th1, NULL);
	pthread_join(th2, NULL);
	printf("s1 = %d, s2 = %d, s1+s2 = %d\n", args1.result, args2.result, args1.result+args2.result);
	return 0;
}

这样在func函数中,我们就可以对传入的结构体参数中的元素进行利用了,将计算所得传到结构体的result中去。这样我们输出加法和,就可以得到跟上面一样的结果,但是代码会更整洁漂亮

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

// 基于线程的并发编程
#include <stdio.h>
#include <pthread.h>
#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<NUM_Threads; i++)
    {
       ret = pthread_create(&tids[i], NULL, PrintHello, NULL);	//参数依次是: 创建的线程ID,线程参数,调用的函数,传入的函数参数
       if (ret != 0)
      {
          printf("pthread_create error: error_code = \n");
      }
    }
    // 等各个线程退出后,进程才结束
    pthread_exit(NULL);
 
    return 0;
}

/*输出结果为:
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!*/

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

// 基于线程的并发编程,向线程传递参数1
// Test_2_createThread
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#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;
    int indexes[NUM_Threads];	//用数组存储i的数值
 
    for (i=0; i<NUM_Threads; i++)
    {
        printf("main() : 创建线程 %d \n",i);
        indexes[i] = i; // 保存i的数值
        rc = pthread_create(&pthreads[i], NULL, PrintHelloId, (void *)&indexes[i]);	//在indexes传入参数的时候必须转换为无类型指针
        if (0 != rc)	//创建线程失败
        {
            printf("Error: 无法创建线程!\n");
            exit(-1);
        }
    } 
    pthread_exit(NULL);
    return 0;
}
 
/*输出结果为:
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*/

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

如何向线程函数传递多个参数

// 基于线程的并发编程,向线程传递参数2(传递结构体)
// Test_3_createThread
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#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;
}
 
/*输出结果为:
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_createThread
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
 
#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<NUM_Pthread; 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<NUM_Pthread; 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;
}

信号量机制

信号量同步进行写入

// 用信号量进行同步
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <semaphore.h>
 
#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;
}

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

// 用互斥信号量进行同步
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
 
#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<NUM_Pthread; 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<NUM_Pthread; 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<NUM_Pthread; i++)
    {
        // 汇合线程
        pthread_join(Pthread[i], NULL);
    }
    printf("count = %d\n",count);
    pthread_exit(NULL);
    return 0;
}
 
// 在运行此程序无互斥锁时,我们不仅得到错误的答案,而且每次得到的答案都不相同
// 分析
// 当多个对等线程在一个处理器上并发运行时,机器指令以某种顺序完成,每个并发执行定义了线程中指令的某种顺序
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶雨莳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值