I haven't coded much for probably a few years, and I wanted to make a really basic thread manager in C++ for an idea I had. I have ran into an issue where I get this error:
ThreadManager.cpp:49:37: error: cannot convert
'ThreadManager::updateLoop' from type 'DWORD (ThreadManager::)(LPVOID)
{aka long unsigned int (ThreadManager::)(void*)}' to type
'LPTHREAD_START_ROUTINE {aka long unsigned int
(attribute((stdcall)) )(void)}'
Yet, I don't know how to attempt to fix it. Here is my code, I couldn't figure out how to paste it in here with formatting. It said I needed 4 spaces on each line but that seemed like would take a while, so I put it on pastebin:
ThreadManager.cpp: http://pastebin.com/2bL3mTqv
ThreadManager.h: http://pastebin.com/7xETj5BK
Like I said, I haven't programmed much for a LONG time, and I am trying to get back into it with what I remember, so any help would be appreciated.
The comments have said the basics, but here's it spelled out: you can't pass in a method to a class when a call is expecting a normal function. To do what you want, I'd do the following:
// New Function
void threadMain(void* classPointer)
{
ThreadManager* realClass = (ThreadManager*)classPointer;
realClass->updateLoop();
}
ThreadManager::ThreadManager(int max)
{
// Assign maxThreads to max value
maxThreads = max;
// Start updateThread, and let it run updateLoop() until terminated
updateThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
threadMain, // thread function name
this, // argument to thread function
0, // use default creation flag
NULL); // ignore thread identifier
// Check the return value for success
// If failed, exit process.
if (updateThread == NULL) {
ExitProcess(3);
}
}
Now I know you want an extra argument, so probably use std::tuple to pass in the "this" pointer and any extra arguments you actually want.
Now having said all of that, take the advice of others and use std::thread and such, not the win32-specific calls unless you really need to.
Related
I am trying to figure out how to assign a message field in protobuf2 in C++. Here is a small snippet of the code.
message Sub {
optional double x = 1 [[default = 46.0];
}
message Master {
optional Sub sub_message;
}
Now when I try to initialize a Master message, I got the following error:
Master msg;
msg.mutable_sub_message() = new Sub();
error: expression is not assignable
However, the following code works, and the sub_message is set to default values:
Master msg;
msg.set_sub_message(new Sub());
Can anyone kindly explain why mutable_sub_message() can not be used for assignment?
msg.mutable_sub_message() returns a pointer to the field, i.e. a Sub*. The idea is that you use that pointer to manipulate the field as you need.
Assigning a different pointer to it wouldn't change the value inside the class, it would at most change the temporary pointer that was returned, which doesn't make sense. I guess it could be made to work if mutable_sub_message returned something like a Sub*& (not even sure that syntax is right), but that's not how the library was written.
In a more practical note, calling mutable_sub_message will initialize the subfield, you don't need to do that explicitly. That means you'd usually set a nested field using
Master msg;
msg.mutable_sub_message()->set_x(4.0);
Also, it's always safe to call getters even if a field isn't set, in that case they will always return a default instance. In other words:
double use_field(const Master& msg) {
// This is always safe, and will return the default even if
// sub_message isn't set.
return msg.sub_message().x();
}
I'm writing an Object Oriented version of FCFS scheduling algorithm, and I've hit a problem. I need to know if there's any way to access an array of objects inside the member function definition, without passing it as a parameter explicitly.
I've tried using "this-pointer", but since the calculation of finish time of current process requires the finish time of the previous, "this" won't work. Or at least I think it won't. I have no idea how to access "previous" object using "this"
void Process :: scheduleProcess(int pid) {
if(pid == 0) finishTime = burstTime;
else finishTime = burstTime +
this->[pid-1].finishTime;
turnAroundTime = finishTime - arrivalTime;
waitingTime = turnAroundTime - burstTime;
}
I can obviously send the array of objects as a parameter and use it directly. I just want to know if there's a better way to do this:
This is the part that's calling the aforementioned function:
for(int clockTime = 0; clockTime <= maxArrivalTime(process);
clockTime++) {
// If clockTime occurs in arrivalTime, return pid of that
process
int pid = arrivalTimeOf(clockTime, process);
if(pid >= 0) {
process[pid].scheduleProcess(pid);
} else continue;
}
Since I'm calling scheduleProcess() using process[pid], which is a vector of objects, I should be able to manipulate the variables pertaining to process[pid] object. How do I access process[pid-1] in the function itself? (Without passing process vector as an argument)
Since scheduleProcess is a member of Process, it only knows what the Process object knows. The previous process is unknown at this level. There are ways that use Undefined Behavior and make more assumptions about your code to get around this, but these should be avoided.
One portable solution to avoid all that is to simply pass in the previous process's finish time as a parameter, since you know this value at the point of the call to scheduleProcess. Where there is not a previous process (the first entry in the array), this finish time would be 0.
I have to send the parameter "r" of type "risposta" to the function RispostaServer. The compiler gives me: invalid conversion void*(*)() to void*(*)(void*)
Here's the code fragment that i should correct:
{/*other istructions*/
risposta r;
r.mess = m1;
r.codaSC = codaSC;
pthread_create(&threads[threads_index],&attr,RispostaServer,(void*)&r);
threads_index++;
}
void* RispostaServer(void* m){
risposta* m1 = (risposta*) m;
/*other istructions*/
}
What should i edit ? I'm trying it by hours.
I'll take a stab in the dark at this, pre-[MCVE] (but please do provide one).
Does your declaration for RispostaServer look like this?
void* RispostaServer();
Then the only version of RispostaServer visible to the pthread_create call is one that doesn't take an argument. That matches the type complaint kicked out by the compiler.
Your later function definition creates a new overload of RispostaServer that does take an argument, and you'd be able to call that lower down the code, but it's too late for the pthread_create call by then.
The declaration should match the definition:
// Entrypoint for Risposta worker thread.
// Argument must be a risposta*, cast to `void*`.
void* RispostaServer(void* m);
By the way, your thread will be broken because you're passing in a pointer to a local variable that immediately goes out of scope, so add the following comment to the above:
// The risposta it points to must exist for the lifetime
// of the thread.
…and you really ought to be using std::thread rather than the C API of a platform-specific library.
This is my first time posting my own question, so sorry if I break etiquette or something in some way. Most of the software in this program I'm working on wasn't coded by me. I'm wanting to create a thread using one of their functions.The function I want to implement in the thread looks like this. If possible I would like to be able to continue using pthreads:
void * bpsk_continuous(
uhd::usrp::multi_usrp::sptr usrp,
const std::string &cpu_format,
const std::string &wire_format,
const std::string &file,
size_t samps_per_buff,
unsigned long long num_requested_samples,
double time_requested = 0.0,
bool bw_summary = false,
bool stats = false,
bool null = false,
bool enable_size_map = false,
bool continue_on_bad_packet = false
){//operations of function}
Later they use syntax very unfamiliar to me that I'm assuming defines the arguments in some way. My first question would be what is the following code doing.
#define bpsk_continuous_args(format) \
(usrp, format, wirefmt, file, spb, total_num_samps, total_time, bw_summary, stats, null, enable_size_map, continue_on_bad_packet)
//if (type == "float") recv_to_file<std::complex<float> >recv_to_file_args("fc32");
My second question would be how can I create a thread that runs the bpsk_continuous argument given the syntax above. I tried the following but no dice:
pthread_t t1;
pthread_create(&t1, NULL, bpsk_continuous,bpsk_continuous_args("fc32"));
You should create auxiliary struct, and the start routine, lets say:
struct bpsh_args {
uhd::usrp::multi_usrp::sptr usrp;
std::string cpu_format;
std::string wire_format;
std::string file;
size_t samps_per_buff;
unsigned long long num_requested_samples;
double time_requested;
bool bw_summary;
bool stats;
bool null;
bool enable_size_map;
bool continue_on_bad_packet;
};
In the start routine you should cast it's only argument back to bpsh_args:
void* start_routine(void* _args) {
bpsh_args* args = static_cast<bpsh_args*>(_args);
bpsk_continuous(args->usrp, args->cpu_format, ...);
}
Then fill bpsh_args with appropriate data and then pass the pointer to it as last argument of pthread_create, and start_routine as one before last.
bpsh_args _bpsh_args;
_bpsh_args.usrp = ....;
_bpsh_args.cpu_format = "fc32";
...
pthread_create(&t1, NULL, start_routine, &_bpsh_args);
Consult man or http://man7.org/linux/man-pages/man3/pthread_create.3.html for details.
Be aware of the fact that after a new thread is started the struct with arguments is shared between two threads and the _args will be invalid if the variable _bpsh_args goes out of scope. Maybe you should better allocate it on heap, or add some synchronisation primitives to ensure that _bpsh_args is alive as long as you use it in descendant thread.
To answer your first question, what the #define does, it is a so-called macro. Macros just perform text replacement. Just do a little research and you will find out more about them, in particular that they are generally considered an evil feature of C++.
Then, if you need to rule out using a portable approach like std::thread (or even Boost's variant thereof), try this approach:
void* thread_function(void* arg)
{
assert(arg);
std::string const& format = *static_cast<std::string*>(arg);
return bpsk_continuous bpsk_continuous_args(format);
}
somewhere()
{
std::string format = ...;
pthread_create(.., &thread_function, &format, ..);
}
Note that this library is from what I can tell shoddy C++. The use of lower-case macros. Using them to work around its own overly long parameter lists. The seeming lack of understanding for namespaces. These all seems like a poor design choices to me and I wouldn't be surprised to find more of them.
I have a class called CSum which contains a static method who's identifier is:
static double fileProc(string myFile);
In my main function I would simply call it by
CSum::fileproc("foo.txt")
However, I will like to invoke pthreads on two separate files. Therefore I need to obtain the address of this method. I do so by
return1 = pthread_create(&t1, NULL, &CSum::fileProc(file1), NULL);
return2 = pthread_create(&t2, NULL, &CSum::fileProc(file2), NULL);
But I get an error
lvalue required as a unary '&' operand.
Any suggestions?
You don't pass parameters, you just give the name of the function. The parameter you want it to get is the next parameter of the pthread_create.
Instead of
pthread_create(&t2, NULL, &CSum::fileProc(file2), NULL);
do
pthread_create(&t2, NULL, &CSum::fileProc, file2);
Cast types as appropriate. Note that the thread function is supposed to accept a pointer as a parameter, make sure you define it appropriately.
CSum::fileProc(file1) is an expression that calls the function and gives you the value the function returns as the value of the expression. You are trying to take the address of that value, which you can't, and this won't do what you want.
&CSum::fileProc will give you the function pointer, but it does not have the correct signature for use with pthreads. Since pthreads is a C library, it has a very simplistic interface. Your best bet for C++ is to use a higher-level C++ library that uses pthreads underneath (at least on unixes), like boost threads.
If for some reason yoou can't do that, you need to write your own wrappers. To call your function in a separate thread, you would need to write something like:
class CSum {
...
static void fileProcWrapper(void* param) {
const char* fileName = (const char*) param;
fileProc(fileName);
}
...
and call it with
pthread_create((&t2, NULL, &CSum::fileProc, (void*) file1.c_str());
That just gives you the call, mind, the result is thrown away with this code. If you want to collect the result with pthread_join, you have to do a bit more work.