linux程序设计------进程和线程的学习

进程:程序代码+数据+变量(占用着系统内存)+文件描述符(打开的文件)+环境
p408模拟一个闹钟alarm.c
线程:新的执行线程拥有自己的栈存储局部变量,但与他的创建者共享全局变量、文件描述符、信号处理函数、当前目录状态。

#include 
#include 
#include 
#include //pause函数
#include 

static int alarm_fired = 0;//标志

void ding(int sig)//模拟闹钟,参数为信号
{
	alarm_fired = 1;//闹钟唤醒,标志设为1
}

//告诉子进程在等待5秒后发送一个SIGALRM信号(超时警告)给他的父进程
int main()
{
	pid_t pid;
	printf("alarm application atarting\n");
	
	pid = fork();//建立子进程
	switch(pid){
	case -1:
		perror("fork failed");
		exit(1);
	case 0:
		//child
		sleep(5);//子进程等待五秒
		kill(getppid(),SIGALRM);//向父进程发送一个超时警告信号
		exit(0);
	}

	//父进程通过一个signal调用安排好捕获信号的工作,等待超时警告信号的到来
	//并未在信号处理函数ding中使用printf,而是设置标志位,在main函数中printf完成消息输出
	printf("waiting for alarm to go off\n");
	(void) signal(SIGALRM, ding);
	
	pause();//把程序暂时挂起,直到有一个信号出现为止,被信号中断时返回

	if(alarm_fired)
		printf("Ding!\n");
	printf("Done\n");
	exit(0);
}

//使用信号并挂起程序的执行很重要
//利用更健壮的信号接口sigaction代替signal
#include 
#include 
#include 

void ouch(int sig)
{
	printf("OUCH! - I got signal %d\n", sig);
}

int main()
{
	struct sigaction act;//包含:信号处理函数、信号屏蔽字、标志

	act.sa_handler = ouch;
	sigemptyset(&act.sa_mask);//创建空的信号屏蔽字:当前被阻塞的一组信号,不能被当前信号接收到,阻止竞态的一种方式
	act.sa_flags = 0;
	sigaction(SIGINT, &act, 0);

	while(1){
		printf("Hello world!\n");
		sleep(1);
	}
}

//Ctrl + C组合键:看到消息
//终止:Ctrl+\组合键

信号量:可以控制对一组相同对象那个的访问,比如从5条可用的电话线中分配1条给某个线程的情况,更适合用计数信号量。
互斥量:控制任一时刻只能有一个线程可以访问一些共享内存

例子:用信号量和双线程实现统计从键盘输入的字符串个数

#include 
#include 
#include 
#include 
#include 
#include  //访问信号量函数

const int WORK_SIZE = 1024;

void *thread_function(void *arg);
sem_t bin_sem; //信号量
char work_area[WORK_SIZE];

int main()
{
    int res;
    pthread_t a_thread;
    void *thread_result; //指向任意类型的指针

    //信号量的创建并初始化,初始值设为0,这样新线程启动时,sem_wait函数调用会阻塞并等待信号量变为非0值
    //int sem_init(sem_t *sem, int pshared, unsigned int value);
    //pshared:控制信号量类型,0代表信号量是当前进程的局部信号量
    res = sem_init(&bin_sem, 0, 0);

    if (res != 0)
    {
        perror("Semaphore initialization failed");
        exit(EXIT_FAILURE);
    }

    res = pthread_create(&a_thread, NULL, thread_function, NULL); //新线程刚启动会阻塞,程序往下运行

    if (res != 0)
    {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }

    printf("Input some text.Enter 'end' to finish\n");
    while (strncmp("end", work_area, 3) != 0)
    {
        fgets(work_area, WORK_SIZE, stdin); //从键盘读取一些文本
        sem_post(&bin_sem);                 //增加信号量的值,增加后,信号量不为0, 不在阻塞,执行线程函数,计数并减小一个信号量再次阻塞
    }

    printf("\nWaiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0)
    {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    printf("Thread joined\n");
    sem_destroy(&bin_sem);
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg)
{ //新线程:等待信号量,统计来自输入的字符个数
    sem_wait(&bin_sem);
    while (strncmp("end", work_area, 3) != 0)
    {
        printf("You input %d characters\n", strlen(work_area) - 1);
        sem_wait(&bin_sem);
    }
    pthread_exit(NULL);
}

改进:让主线程等到统计线程完成字符串个数的统计后再继续执行,可以使用互斥量!

用互斥量进行同步

锁住某个对象,使得每次只能有一个线程访问它.

#include 
#include 
#include 
#include 
#include 

#include 

//使用互斥量对关键变量进行保护
#define WORK_SIZE 1024
char work_area[WORK_SIZE];
pthread_mutex_t work_mutex; //protects both work_area and time_to_exit
int time_to_exit = 0;

void *thread_function(void *arg);

int main()
{
    int res;
    pthread_t a_thread;
    void *thread_result;

    res = pthread_mutex_init(&work_mutex, NULL); //初始化互斥量,可以设置属性
    if (res != 0)
    {
        perror("Mutex initialization failed");
        exit(EXIT_FAILURE);
    }

    res = pthread_create(&a_thread, NULL, thread_function, NULL); //新建线程
    if (res != 0)
    {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }

    pthread_mutex_lock(&work_mutex); //上锁,以下代码需要被保护,同一时刻只能有一个线程访问
    printf("Input some text.Enter 'end' to finish\n");
    while (!time_to_exit) //没有输入end,继续等待输入字符串
    {
        fgets(work_area, WORK_SIZE, stdin);
        if (work_area[0] != '\0')
        {
            pthread_mutex_unlock(&work_mutex); //解锁以便副线程访问并统计
            sleep(1);
        }
        else
        {
            break;
        }
    }
    pthread_mutex_unlock(&work_mutex);
}

void *thread_function(void *arg) //统计输入字符串个数
{
    sleep(1);
    pthread_mutex_lock(&work_mutex); //统计的时候,对输入字符串代码区上锁
    while (strncmp("end", work_area, 3) != 0)
    {
        printf("You input %d characters\n", (int)strlen(work_area) - 1); //统计字符串,之后解锁

        work_area[0] = '\0';               //第一个字符设置为NULL,用来通知字符个数已统计完成
        pthread_mutex_unlock(&work_mutex); //解锁,继续执行至主线程,等待输入
        sleep(1);
        pthread_mutex_lock(&work_mutex); //上锁后检查是否有输入
        while (work_area[0] == '\0')     //没有输入继续周期性等待,有输入则统计
        {
            pthread_mutex_unlock(&work_mutex); //执行输入主线程
            sleep(1);
            pthread_mutex_lock(&work_mutex);
        }
    }
    //end退出后,解锁等待下一次输入
    time_to_exit = 1;
    work_area[0] = '\0';
    pthread_mutex_unlock(&work_mutex);
    pthread_exit(0);
}
//note:这里没有判断是否加锁,解锁是否成功,而且通过轮询的方式获得结果的方法不是好的编程方式,实际中,应尽可能的使用信号量来避免这种情况

 

你可能感兴趣的:(Linux程序设计)