(Linux)操作系统——线程实验

操作系统一实验3
线程
■目的
深入理解线程及线程在调度执行和内存空间等方面的特点, 并掌握线程与进程的区别。掌握POSIX规范中pthread create( )函数的功能和使用方法。
■实验前准备
阅读参考资料,了解线程的创建等相关系统调用

实验准备:
线程创建函数:pthread_create(&pthread_id[i] , NULL , thread_work , ( void* ) & ( index[ i ] ) );
第一个参数:把创建出来的线程的编号传给pthread_id[ i ];
第二个参数:一般为NULL;
第三个参数:简单理解为该线程执行什么样的工作。
第四个参数:一般来说把第四个参数传到第三个参数中。

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<ctype.h>
#include<pthread.h>

#define MAX_THREAD 3
unsigned long long main_counter,counter[MAX_THREAD];
void* thread_work(void*);
int main(int argc,char*argv[])
{
	int i,rtn,ch;
	int index[MAX_THREAD];
	
	pthread_t pthread_id[MAX_THREAD] = {0};
	for(int i = 0 ; i < MAX_THREAD;i++)
	{
		index[i] = i;
		pthread_create(&pthread_id[i],NULL,thread_work,(void *)&(index[i]));//把整数类型的地址转换成void类型的地址,这样能传到		void* thread_work(void*)中。
			}
	do
	{
		unsigned long long sum  = 0;
		for(int i = 0 ; i < MAX_THREAD;i++)
		{
			sum+=counter[i];
			printf("%llu ",counter[i]);
			printf("%llu/%llu",main_counter,sum);
		}
	}while((ch = getchar()) != 'q');
	return 0;
}

void *thread_work(void *p)
{
	int thread_num = *((int *)p);
	for(;;)
	{
		counter[thread_num]++;
		main_counter++;
	}
}

运行结果:
在这里插入图片描述

程序解读:
(1)程序执行之后,进程有一个主线程,三个子线程。程序执行完,主线程结束,三个子线程会强行结束。
(2)之所以最后main_counter和三个counter[ i ]不同,是因为三个线程共享一个main_counter,导致并发执行
main_counter++,但是每个counter[ i ]是正常加,所以main_counter比三个counter[ i ]相加要小。
(3)三个counter[ i ]占用CPU的效率近似相同,但并不完全相同,与时间片轮转有关。

正确代码:

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<ctype.h>
#include<pthread.h>

#define MAX_THREAD  3  //线程个数

//初始化锁
static pthread_mutex_t    mutex = PTHREAD_MUTEX_INITIALIZER;

unsigned long long   main_counter,counter[MAX_THREAD]={0};

void* thread_worker(void*  arg)
{
    //先将void* 转为 int* 再赋值
    int  thread_num = *(int*)arg;
    //释放内存
    free((int*)arg);
    for(;;)
    {
        //加锁
        pthread_mutex_lock(&mutex);
        counter[thread_num]++;    //本线程的counter 加 1
        main_counter++;
        //解锁
        pthread_mutex_unlock(&mutex);
        //sleep(3);
    }
}

int main(int argc,char* argv[])
{
    int                 i,rtn,ch;
    pthread_t           pthread_id[MAX_THREAD] =  {0};  //存放线程

    int                 *param;
    for(i=0;i<MAX_THREAD;i++)
    { 
        //申请内存临时保存参数
        param = (int*)malloc(sizeof(int));
        *param = i;
        pthread_create(&pthread_id[i],NULL,thread_worker,param);
    }

    do
    {
        //加锁
        pthread_mutex_lock(&mutex);
        unsigned long long   sum = 0;
        for(i=0;i<MAX_THREAD;i++)
        {
            sum += counter[i];
            printf("No.%d: %llu\n",i,counter[i]);
        }
        printf("%llu/%llu\n",main_counter,sum);
        //解锁
        pthread_mutex_unlock(&mutex);
    }while((ch = getchar())!='q');

    //销毁锁资源
    pthread_mutex_destroy(&mutex);
    return 0;
}

这里解释一下两个加锁的地方:
1.第一个加锁的地方在工作函数,如果工作函数不加锁,3个子线程会竞争一个main_counter资源,导致数据会和3个counter之和不同,main_counter比较小。
2.第二个加锁的地方在do_while循环里面,这里如果不加虽然主线程已经加过3个counter,但是子线程还在运行,main_counter还在增加。导致main_counter比较大

猜你喜欢

转载自blog.csdn.net/qq_40240576/article/details/83002925
今日推荐