MAC COCOA一个简单的多线程程序[2]
使用RUNLOOP计数,实现一个时间计数器和事件at the same time 运行。
STEP 1
H
CODE:
//
// EDUAppDelegate.h
// test_runloop_multithread
//
// Created by DMD on 23/6/14.
// Copyright (c) 2014 EDU. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface EDUAppDelegate : NSObject <NSApplicationDelegate>
@property (assign) IBOutlet NSWindow *window;
@property (assign) IBOutlet NSTextField *m_Label_TotalCount;
@property (assign) IBOutlet NSTextField *m_Label_EveryStartCount;
@property (assign) IBOutlet NSTextField *m_Edit_SetCurrentNumber;
@property (assign) IBOutlet NSTextField *m_Label_EveryStartCount_Set;
@property (assign) IBOutlet NSTextField *m_Label_Restart;
@property CFRunLoopSourceRef m_source1;
@property CFRunLoopSourceContext m_source1_context;
@property CFRunLoopTimerRef m_timer1;
@property CFRunLoopTimerContext m_timer1_context;
@property NSString *m_total_str;
@property int m_total_count;
-(void)Show_Msg;
-(void) set_label_value:(int)value;
@end
M
CODE:
//
// EDUAppDelegate.m
// test_runloop_multithread
//
// Created by DMD on 23/6/14.
// Copyright (c) 2014 EDU. All rights reserved.
//
/****************************************
Function : 1个线程来计数,另一个线程来接受用户输入的字符串,互相之间不干扰
目的:测试多线程程序工作,了解原理
*****************************************/
#import "EDUAppDelegate.h"
//Define Public Variable +++++
static int g_total_count=0;
static EDUAppDelegate *m_window_main;
//---------------------------
@implementation EDUAppDelegate
//define var +++
@synthesize m_Edit_SetCurrentNumber;
@synthesize m_Label_EveryStartCount;
@synthesize m_Label_EveryStartCount_Set;
@synthesize m_Label_TotalCount;
@synthesize m_Label_Restart;
@synthesize m_source1;
@synthesize m_source1_context;
@synthesize m_timer1;
@synthesize m_timer1_context;
@synthesize m_total_count;
@synthesize m_total_str;
//---------------
- (void)dealloc
{
[super dealloc];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
m_window_main = self;
m_total_count=0;
m_total_str=@"";
}
-(void) set_label_value:(int)value
{
NSString *myname;
myname = [NSString stringWithFormat:@"Every Start Count:%d",value];
m_total_str = [m_total_str stringByAppendingString:myname];
m_total_str = [m_total_str stringByAppendingString:@"\n"];
m_Label_EveryStartCount.stringValue = m_total_str;
if((m_total_count>0 )&&(m_total_count % 5 ==0))
{
m_total_str=@"";
m_Label_Restart.stringValue = @"Re-Start 0";
m_total_count =0;
[self Show_Msg];
}
}
//+++++[一个多线程里面调用的函数,C++方式的函数,而不是Object-C方式]
// Call Function (2 Method)++
// Do thing 1
void my_do1(void *info __unused)
{
m_window_main.m_total_count++;
printf("Every Start Count: [%d] \n",m_window_main.m_total_count );
[m_window_main set_label_value:m_window_main.m_total_count];
g_total_count++;
printf("Total Count is :\"%d\" \n",g_total_count );
m_window_main.m_Label_TotalCount.stringValue =[NSString stringWithFormat:@"Number is [%d]",g_total_count];
}
// Timer Function 1
void timer_function1(CFRunLoopTimerRef timer __unused, void *info)
{
CFRunLoopSourceSignal(info);
}
// Call Function (2 Method)--
// START
- (IBAction)OnBT_Start:(id)sender
{
// 每一次Start时,一些变量需要Clear
// 句柄:m_window_main 是本类的指针,必须初始化,一般为[ClassName1 alloc]init
// 这里使用的是本身类,就直接 =self就可以了。
m_window_main.m_total_count =0;
m_Label_Restart.stringValue = @"Start!";
m_total_str=@"";
// 第一个线程:执行的事件 [begin] ++++++++
//STEP 1 : [线程内容]初始化CFRunLoopSourceContext的空间
bzero(&m_source1_context, sizeof(m_source1_context));
//STEP 2 : [线程内容]调用要执行的函数
m_source1_context.perform = my_do1;
//STEP 3 : [线程源]初始化CFRunLoopSourceRef
m_source1 = CFRunLoopSourceCreate(NULL, 0, &m_source1_context);
//STEP 4 : 将线程源加到当前线程里面去
CFRunLoopAddSource(CFRunLoopGetCurrent(), m_source1, kCFRunLoopCommonModes);
//STEP 5 : 执行完,将线程源释放
CFRelease(m_source1);
// 第一个线程:执行的事件 [end] ++++++++
// 第二个线程:一个时间计数器,用来启动上面的事件线程 [begin]+++++++++
// STEP 1 初始化时间线程内容空间
bzero(&m_timer1_context, sizeof(m_timer1_context));
// STEP 2 [非常关键] 时间计数器的内容源头是上面的事件源头
m_timer1_context.info = m_source1;
// STEP 3 生成时间线程源头句柄
m_timer1 = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(), 1, 0, 0,
timer_function1, &m_timer1_context);
// STEP 4 将时间源加入到时间计数列表里面
CFRunLoopAddTimer(CFRunLoopGetCurrent(), m_timer1, kCFRunLoopCommonModes);
CFRelease(m_timer1);
//第二个线程:一个时间计数器,用来启动上面的事件线程 [end]--------
//如果不用,就会在执行中,可以做其他的事件。但是在DOS环境状态,必须有这一行,在编译时才能看到。
// CFRunLoopRun();
}
// STOP
- (IBAction)OnBT_Stop:(id)sender
{
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_source1, kCFRunLoopCommonModes);
CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), m_timer1, kCFRunLoopCommonModes);
m_Label_Restart.stringValue = @"Stop!";
}
- (IBAction)OnBT_SetEveryStartCountNo:(id)sender
{
m_Label_EveryStartCount_Set.stringValue = m_Edit_SetCurrentNumber.stringValue;
g_total_count = [m_Label_EveryStartCount_Set.stringValue intValue];
}
- (IBAction)OnBT_CallSelfFunction:(id)sender
{
[self OnBT_SetEveryStartCountNo:self];
}
// Show a MessageBox
-(void)Show_Msg
{
NSAlert *alert = [[[NSAlert alloc] init]autorelease];
[alert setMessageText:@"Label captio is :"];
[alert setInformativeText:@"Close"];
[alert setAlertStyle:NSWarningAlertStyle];
[alert runModal];
}
@end
运行效果图:
成功!
需要补充:在定义自身类的时候,一定要初始化 =self,这样才可以使用本身类里面的成员函数或者变量
完成!
特别补充,当你的工程里面加入了iostream等C++代码的时候,就需要将m后缀名修改为mm
这时候就需要将
CFRunLoopSourceSignal((CFRunLoopSourceRef)info);
强制转换1下就可以了。
此语句在m文件里面也可以用。
修改方法,当说不匹配的时候,查找这个函数,发现类型和调用的void不同,就要强制转换。
完。